comparison src/post.c @ 115:3b4db42990e0 noffle

[svn] Approved: header, group check before post, all external servers.
author bears
date Sat, 24 Jun 2000 21:47:40 +0100
parents af51bf245bc3
children d45b0abe7c79
comparison
equal deleted inserted replaced
114:af7bea7515b2 115:3b4db42990e0
1 /* 1 /*
2 post.c 2 post.c
3 3
4 $Id: post.c 123 2000-05-26 09:46:29Z bears $ 4 $Id: post.c 159 2000-06-24 20:47:40Z bears $
5 */ 5 */
6 6
7 #if HAVE_CONFIG_H 7 #if HAVE_CONFIG_H
8 #include <config.h> 8 #include <config.h>
9 #endif 9 #endif
39 struct Article 39 struct Article
40 { 40 {
41 DynStr *text; /* Processed article text */ 41 DynStr *text; /* Processed article text */
42 ItemList *newsgroups; /* Newsgroups for dispatch */ 42 ItemList *newsgroups; /* Newsgroups for dispatch */
43 ItemList *control; /* Control message? NULL if not */ 43 ItemList *control; /* Control message? NULL if not */
44 Bool posted; /* Has it been put in the article database? */ 44 Bool approved; /* Has Approved: header? */
45 const char *server; /* Server for external post */ 45 Bool posted; /* Has it been put in the article database? */
46 struct OverInfo over; 46 struct OverInfo over;
47 }; 47 };
48 48
49 static struct Article article = { NULL, NULL, NULL, FALSE, NULL, 49 static struct Article article = { NULL, NULL, NULL, FALSE, FALSE,
50 { "", "", "", "", "", 0, 0 } }; 50 { "", "", "", "", "", 0, 0 } };
51 51
52 /* Add the article to a group. */ 52 /* Add the article to a group. */
53 static Bool 53 static Bool
54 addToGroup( const char * grp ) 54 addToGroup( const char * grp )
93 Grp_setFirstLast( Cont_grp(), Cont_first(), Cont_last() ); 93 Grp_setFirstLast( Cont_grp(), Cont_first(), Cont_last() );
94 return TRUE; 94 return TRUE;
95 } 95 }
96 96
97 static Bool 97 static Bool
98 checkPostableNewsgroup( Bool localOnly ) 98 checkPostableNewsgroup( void )
99 { 99 {
100 const char *grp; 100 const char * grp;
101 Bool knownGrp = FALSE; 101 Bool knownGrp = FALSE;
102 Bool postAllowedGrp = FALSE; 102 Bool postAllowedGrp = TRUE;
103 Bool local; 103 Bool local;
104 104
105 /* 105 /*
106 Check at least one group is known. Look for external group and 106 * Check all known groups are writeable, and there is
107 set server. 107 * at least one known group.
108 */ 108 */
109 article.server = NULL;
110 for( grp = Itl_first( article.newsgroups ); 109 for( grp = Itl_first( article.newsgroups );
111 grp != NULL; 110 postAllowedGrp && grp != NULL;
112 grp = Itl_next( article.newsgroups ) ) 111 grp = Itl_next( article.newsgroups ) )
113 { 112 {
114 if ( Grp_exists( grp ) ) 113 if ( Grp_exists( grp ) )
115 { 114 {
116 local = Grp_local( grp ); 115 local = Grp_local( grp );
117 if ( localOnly && ! local )
118 continue;
119 knownGrp = TRUE; 116 knownGrp = TRUE;
120 switch( Grp_postAllow( grp ) ) 117 switch( Grp_postAllow( grp ) )
121 { 118 {
122 case 'n': 119 case 'n':
123 if ( localOnly ) 120 postAllowedGrp = FALSE;
124 postAllowedGrp = TRUE;
125 break; 121 break;
126 case 'y': 122 case 'y':
127 postAllowedGrp = TRUE; 123 break;
124 case 'm':
125 /*
126 * Can post to moderated groups if *either*
127 * 1. Group is local and article approved, or
128 * 2. Group is external
129 */
130 postAllowedGrp =
131 ! local ||
132 article.approved;
128 break; 133 break;
129 default: 134 default:
130 if ( localOnly ) 135 /*
131 postAllowedGrp = TRUE; 136 * Unknown mode for local groups. Forward
132 else 137 * to server for external groups; presumably the
133 /* Can't post to moderated local groups. */ 138 * server knows what to do.
134 postAllowedGrp = ! local; 139 */
140 postAllowedGrp = ! local;
135 break; 141 break;
136 } 142 }
137 if ( postAllowedGrp && ! local && article.server == NULL )
138 article.server = Grp_server( grp );
139 if ( postAllowedGrp && article.server != NULL )
140 break;
141 } 143 }
142 } 144 }
143 145
144 if ( ! knownGrp ) 146 if ( ! knownGrp )
145 { 147 {
146 Log_err( "No known group in Newsgroups header field" ); 148 Log_err( "No known group in Newsgroups header field" );
147 return FALSE; 149 return FALSE;
148 } 150 }
149 else if ( ! postAllowedGrp ) 151 else if ( ! postAllowedGrp )
150 { 152 {
151 Log_err( "No group permits posting" ); 153 Log_err( "A group does not permit posting" );
152 return FALSE; 154 return FALSE;
153 } 155 }
154 156
155 return TRUE; 157 return TRUE;
156 } 158 }
159 static Bool 161 static Bool
160 getArticleText( const char *p ) 162 getArticleText( const char *p )
161 { 163 {
162 DynStr * s; 164 DynStr * s;
163 Str line, field, value; 165 Str line, field, value;
164 Bool replyToFound; 166 Bool replyToFound, pathFound;
165 time_t t; 167 time_t t;
166 168
167 s = new_DynStr( 10000 ); 169 s = new_DynStr( 10000 );
168 article.text = s; 170 article.text = s;
169 171
170 memset( &article.over, 0, sizeof( article.over ) ); 172 memset( &article.over, 0, sizeof( article.over ) );
171 replyToFound = FALSE; 173 replyToFound = pathFound = FALSE;
172 174
173 /* Grab header lines first, getting overview info as we go. */ 175 /* Grab header lines first, getting overview info as we go. */
174 while ( ( p = Utl_getHeaderLn( line, p ) ) != NULL 176 while ( ( p = Utl_getHeaderLn( line, p ) ) != NULL
175 && line[ 0 ] != '\0' 177 && line[ 0 ] != '\0'
176 && Prt_getField( field, value, line ) ) 178 && Prt_getField( field, value, line ) )
208 else if ( strcmp ( field, "reply-to" ) == 0 ) 210 else if ( strcmp ( field, "reply-to" ) == 0 )
209 { 211 {
210 replyToFound = TRUE; 212 replyToFound = TRUE;
211 DynStr_appLn( s, line ); 213 DynStr_appLn( s, line );
212 } 214 }
215 else if ( strcmp ( field, "approved" ) == 0 )
216 {
217 article.approved = TRUE;
218 DynStr_appLn( s, line );
219 }
220 else if ( strcmp ( field, "path" ) == 0 )
221 {
222 pathFound = TRUE;
223 DynStr_appLn( s, line );
224 }
213 else if ( strcmp ( field, "x-sender" ) == 0 ) 225 else if ( strcmp ( field, "x-sender" ) == 0 )
214 { 226 {
215 DynStr_app( s, "X-NOFFLE-X-Sender: " ); 227 DynStr_app( s, "X-NOFFLE-X-Sender: " );
216 DynStr_appLn( s, value ); 228 DynStr_appLn( s, value );
217 } 229 }
264 Log_ntc( "Replacing invalid Message-ID '%s'", article.over.msgId ); 276 Log_ntc( "Replacing invalid Message-ID '%s'", article.over.msgId );
265 Prt_genMsgId( article.over.msgId, article.over.from, "NOFFLE" ); 277 Prt_genMsgId( article.over.msgId, article.over.from, "NOFFLE" );
266 } 278 }
267 DynStr_app( s, "Message-ID: " ); 279 DynStr_app( s, "Message-ID: " );
268 DynStr_appLn( s, article.over.msgId ); 280 DynStr_appLn( s, article.over.msgId );
281
282 /* Ensure Path header */
283 if ( ! pathFound )
284 {
285 Str path;
286
287 Log_dbg( "Adding Path field to posted message." );
288 DynStr_app( s, "Path: " );
289 Utl_cpyStr( path, Cfg_pathHeader() );
290 if ( path[ 0 ] == '\0' )
291 Prt_genPathHdr( path, article.over.from );
292 DynStr_appLn( s, path );
293 }
269 294
270 /* Ensure Reply-To header */ 295 /* Ensure Reply-To header */
271 if ( ! replyToFound ) 296 if ( ! replyToFound )
272 { 297 {
273 Log_dbg( "Adding Reply-To field to posted message." ); 298 Log_dbg( "Adding Reply-To field to posted message." );
297 322
298 /* Add article to outgoing if needs be */ 323 /* Add article to outgoing if needs be */
299 static Bool 324 static Bool
300 postExternal( void ) 325 postExternal( void )
301 { 326 {
302 if ( article.server == NULL ) 327 const char * grp;
303 return TRUE; 328 Str serversSeen;
304 329 Bool err;
305 if ( ! Out_add( article.server, article.over.msgId, article.text ) ) 330
306 { 331 /*
307 Log_err( "Cannot add posted article to outgoing directory" ); 332 * For each external group, send to that group's server if it has
308 return FALSE; 333 * not seen the post already.
309 } 334 */
310 335 serversSeen[ 0 ] = '\0';
311 return TRUE; 336 err = FALSE;
337
338 for ( grp = Itl_first( article.newsgroups );
339 grp != NULL;
340 grp = Itl_next( article.newsgroups ) )
341 {
342 if ( Grp_exists( grp ) && ! Grp_local( grp ) )
343 {
344 const char * servName = Grp_server( grp );
345
346 if ( strstr( serversSeen, servName ) != NULL )
347 continue;
348
349 if ( ! Out_add( servName, article.over.msgId, article.text ) )
350 {
351 Log_err( "Cannot add posted article to outgoing directory" );
352 err = TRUE;
353 }
354 Utl_catStr( serversSeen, " " );
355 Utl_catStr( serversSeen, servName );
356 }
357 }
358
359 return err;
312 } 360 }
313 361
314 /* Cancel and return TRUE if need to send cancel message on to server. */ 362 /* Cancel and return TRUE if need to send cancel message on to server. */
315 static Bool 363 static Bool
316 controlCancel( const char *cancelId ) 364 controlCancel( const char *cancelId )
354 402
355 return postExternal(); 403 return postExternal();
356 } 404 }
357 405
358 static Bool 406 static Bool
359 postArticle( Bool localOnly ) 407 postArticle( void )
360 { 408 {
361 const char *grp; 409 const char *grp;
362 Bool err; 410 Bool err;
411 Bool local;
363 Bool postLocal; 412 Bool postLocal;
364 Bool local; 413 char postAllow;
365 414
366 err = FALSE; 415 err = FALSE;
367 postLocal = Cfg_postLocal(); 416 postLocal = Cfg_postLocal();
368 417
369 /* Run round & post locally */ 418 /*
419 * Run round first doing all local groups.
420 * Remember, we've already checked it is OK to post to them all.
421 */
370 for( grp = Itl_first( article.newsgroups ); 422 for( grp = Itl_first( article.newsgroups );
371 grp != NULL; 423 grp != NULL;
372 grp = Itl_next( article.newsgroups ) ) 424 grp = Itl_next( article.newsgroups ) )
373 { 425 {
374 local = Grp_local( grp ); 426 local = Grp_local( grp );
375 if ( localOnly && ! local ) 427 if ( ! ( postLocal || local ) )
376 continue; 428 continue;
377 if ( ( local || postLocal ) 429 err = addToGroup( grp ) && err;
378 && ( Grp_postAllow( grp ) == 'y' || localOnly ) ) 430 }
379 err = addToGroup( grp ) && err; 431
380 } 432 return postExternal() && err;
381
382 if ( localOnly )
383 return err;
384 else
385 return postExternal() && err;
386 } 433 }
387 434
388 /* Register an article for posting. */ 435 /* Register an article for posting. */
389 Bool 436 Bool
390 Post_open( const char * text ) 437 Post_open( const char * text )
398 if ( ! getArticleText( text ) ) 445 if ( ! getArticleText( text ) )
399 return FALSE; 446 return FALSE;
400 447
401 if ( Db_contains( article.over.msgId ) ) 448 if ( Db_contains( article.over.msgId ) )
402 { 449 {
450 Post_close();
403 Log_err( "Duplicate article %s.", article.over.msgId ); 451 Log_err( "Duplicate article %s.", article.over.msgId );
404 return FALSE; 452 return FALSE;
405 } 453 }
406 454
407 return TRUE; 455 return TRUE;
408 } 456 }
409 457
410 /* Process the posting */ 458 /* Process the posting */
411 Bool 459 Bool
412 Post_post( Bool localOnly ) 460 Post_post( void )
413 { 461 {
414 if ( ! checkPostableNewsgroup( localOnly ) ) 462 if ( ! checkPostableNewsgroup() )
415 return FALSE; 463 return FALSE;
416 464
417 return ( article.control == NULL ) 465 return ( article.control == NULL )
418 ? ! postArticle( localOnly ) 466 ? ! postArticle()
419 : ! handleControl(); 467 : ! handleControl();
420 } 468 }
421 469
422 /* Done with article - tidy up. */ 470 /* Done with article - tidy up. */
423 void 471 void
436 if ( article.control != NULL ) 484 if ( article.control != NULL )
437 { 485 {
438 del_Itl( article.control ); 486 del_Itl( article.control );
439 article.control = NULL; 487 article.control = NULL;
440 } 488 }
489 article.approved = FALSE;
441 article.posted = FALSE; 490 article.posted = FALSE;
442 article.server = NULL; 491 }
443 } 492
444 493