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 |
