Mercurial > noffle
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 |