comparison server.c @ 26:526a4c34ee2e noffle

[svn] Applied patch from Jim Hague: support for local groups / new command line options --create and --cancel.
author enz
date Sat, 29 Apr 2000 15:45:56 +0100
parents 43631b72021f
children 792eb10e936d
comparison
equal deleted inserted replaced
25:ab6cf19be6d3 26:526a4c34ee2e
1 /* 1 /*
2 server.c 2 server.c
3 3
4 $Id: server.c 18 2000-04-15 10:09:20Z enz $ 4 $Id: server.c 32 2000-04-29 14:45:56Z enz $
5 */ 5 */
6 6
7 #include "server.h" 7 #include "server.h"
8 #include <ctype.h> 8 #include <ctype.h>
9 #include <signal.h> 9 #include <signal.h>
14 #include <unistd.h> 14 #include <unistd.h>
15 #include "client.h" 15 #include "client.h"
16 #include "common.h" 16 #include "common.h"
17 #include "config.h" 17 #include "config.h"
18 #include "content.h" 18 #include "content.h"
19 #include "control.h"
19 #include "database.h" 20 #include "database.h"
20 #include "dynamicstring.h" 21 #include "dynamicstring.h"
21 #include "fetch.h" 22 #include "fetch.h"
22 #include "fetchlist.h" 23 #include "fetchlist.h"
23 #include "group.h" 24 #include "group.h"
25 #include "itemlist.h"
24 #include "lock.h" 26 #include "lock.h"
25 #include "log.h" 27 #include "log.h"
26 #include "online.h" 28 #include "online.h"
27 #include "outgoing.h" 29 #include "outgoing.h"
30 #include "post.h"
28 #include "protocol.h" 31 #include "protocol.h"
29 #include "pseudo.h" 32 #include "pseudo.h"
30 #include "request.h" 33 #include "request.h"
31 #include "util.h" 34 #include "util.h"
32 35
101 noteInterest( void ) 104 noteInterest( void )
102 { 105 {
103 FetchMode mode; 106 FetchMode mode;
104 107
105 Grp_setLastAccess( serv.grp, time( NULL ) ); 108 Grp_setLastAccess( serv.grp, time( NULL ) );
106 if ( Cfg_autoSubscribe() && ! Online_true() ) 109 if ( ! Grp_local ( serv.grp ) && Cfg_autoSubscribe() && ! Online_true() )
107 { 110 {
108 Fetchlist_read(); 111 Fetchlist_read();
109 if ( ! Fetchlist_contains( serv.grp ) ) 112 if ( ! Fetchlist_contains( serv.grp ) )
110 { 113 {
111 if ( strcmp( Cfg_autoSubscribeMode(), "full" ) == 0 ) 114 if ( strcmp( Cfg_autoSubscribeMode(), "full" ) == 0 )
217 static void 220 static void
218 readCont( const char *name ) 221 readCont( const char *name )
219 { 222 {
220 Fetchlist_read(); 223 Fetchlist_read();
221 Cont_read( name ); 224 Cont_read( name );
222 if ( ! Fetchlist_contains( name ) && ! Online_true() ) 225 if ( ! Grp_local ( name )
226 && ! Fetchlist_contains( name )
227 && ! Online_true() )
223 { 228 {
224 Pseudo_appGeneralInfo(); 229 Pseudo_appGeneralInfo();
225 Grp_setFirstLast( name, Cont_first(), Cont_last() ); 230 Grp_setFirstLast( name, Cont_first(), Cont_last() );
226 } 231 }
227 } 232 }
300 retrieveArt( const char *msgId ) 305 retrieveArt( const char *msgId )
301 { 306 {
302 Str serv; 307 Str serv;
303 308
304 findServ( msgId, serv ); 309 findServ( msgId, serv );
305 if ( strcmp( serv, "(unknown)" ) == 0 ) 310 if ( strcmp( serv, "(unknown)" ) == 0 || strcmp( serv, "(local)" ) == 0 )
306 return FALSE; 311 return FALSE;
307 if ( ! Client_connect( serv ) ) 312 if ( ! Client_connect( serv ) )
308 return FALSE; 313 return FALSE;
309 Client_retrieveArt( msgId ); 314 Client_retrieveArt( msgId );
310 Client_disconnect(); 315 Client_disconnect();
423 else if ( stat & DB_NOT_DOWNLOADED ) 428 else if ( stat & DB_NOT_DOWNLOADED )
424 { 429 {
425 findServ( msgId, serv ); 430 findServ( msgId, serv );
426 if ( Req_contains( serv, msgId ) ) 431 if ( Req_contains( serv, msgId ) )
427 putTxtBuf( Pseudo_alreadyMarkedBody() ); 432 putTxtBuf( Pseudo_alreadyMarkedBody() );
428 else if ( strcmp( serv, "(unknown)" ) != 0 && Req_add( serv, msgId ) ) 433 else if ( strcmp( serv, "(unknown)" ) != 0 &&
434 strcmp( serv, "(local)" ) != 0 &&
435 Req_add( serv, msgId ) )
429 putTxtBuf( Pseudo_markedBody() ); 436 putTxtBuf( Pseudo_markedBody() );
430 else 437 else
431 putTxtBuf( Pseudo_markingFailedBody() ); 438 putTxtBuf( Pseudo_markingFailedBody() );
432 } 439 }
433 else 440 else
843 } 850 }
844 } 851 }
845 return TRUE; 852 return TRUE;
846 } 853 }
847 854
855 /* Cancel and return TRUE if need to send cancel message on to server. */
856 static Bool
857 controlCancel( const char *cancelId )
858 {
859 return ( Ctrl_cancel( cancelId ) == CANCEL_NEEDS_MSG );
860 }
861
848 /* 862 /*
849 Get first group of the Newsgroups field content, which is 863 It's a control message. Currently we only know about 'cancel'
850 a comma separated list of groups. 864 messages; others are passed on for outside groups, and logged
851 */ 865 as ignored for local groups.
852 static void 866 */
853 getFirstGrp( char *grpResult, const char *list ) 867 static Bool
854 { 868 handleControl( ItemList *control, ItemList *newsgroups,
855 Str t; 869 const char *msgId, const DynStr *art )
856 const char *src = list; 870 {
857 char *dest = t; 871 const char *grp;
858 while( TRUE ) 872 const char *op;
859 { 873 Bool err = FALSE;
860 if ( *src == ',' ) 874 Bool localDone = FALSE;
861 *dest = ' '; 875
862 else 876 op = Itl_first( control );
863 *dest = *src; 877 if ( op == NULL )
864 if ( *src == '\0' ) 878 {
865 break; 879 Log_err( "Malformed control line." );
866 ++src; 880 return TRUE;
867 ++dest; 881 }
868 } 882 else if ( strcasecmp( op, "cancel" ) == 0 )
869 *grpResult = '\0'; 883 {
870 sscanf( t, "%s", grpResult ); 884 if ( controlCancel( Itl_next( control ) ) )
885 localDone = TRUE;
886 else
887 return err;
888 }
889
890 /* Pass on for outside groups. */
891 for( grp = Itl_first( newsgroups );
892 grp != NULL;
893 grp = Itl_next( newsgroups ) )
894 {
895 if ( Grp_exists( grp ) && ! Grp_local( grp ) )
896 {
897 if ( ! Out_add( Grp_serv( grp ), msgId, art ) )
898 {
899 Log_err( "Cannot add posted article to outgoing directory" );
900 err = TRUE;
901 }
902 break;
903 }
904 }
905
906 if ( localDone )
907 return err;
908
909 /* Log 'can't do' for internal groups. */
910 for( grp = Itl_first( newsgroups );
911 grp != NULL;
912 grp = Itl_next( newsgroups ) )
913 {
914 if ( Grp_exists( grp ) && Grp_local( grp ) )
915 Log_inf( "Ignoring control '%s' for '%s'.", op, grp );
916 }
917
918 return err;
919 }
920
921 static Bool
922 postArticle( ItemList *newsgroups, const char *msgId, const DynStr *art )
923 {
924 const char *grp;
925 Bool err;
926 Bool oneLocal;
927
928 err = oneLocal = FALSE;
929
930 /* Run round first doing all local groups. */
931 for( grp = Itl_first( newsgroups );
932 grp != NULL;
933 grp = Itl_next( newsgroups ) )
934 {
935 if ( Grp_local( grp ) )
936 {
937 if ( ! oneLocal )
938 {
939 if ( ! Post_open( DynStr_str( art ) ) )
940 {
941 err = TRUE;
942 break;
943 }
944 else
945 oneLocal = TRUE;
946 }
947
948 if ( ! Post_add( grp ) )
949 err = TRUE;
950 }
951 }
952 if ( oneLocal )
953 Post_close();
954
955 /* Now look for a valid external group. */
956 for( grp = Itl_first( newsgroups );
957 grp != NULL;
958 grp = Itl_next( newsgroups ) )
959 {
960 if ( Grp_exists( grp ) && ! Grp_local( grp ) )
961 {
962 if ( ! Out_add( Grp_serv( grp ), msgId, art ) )
963 {
964 Log_err( "Cannot add posted article to outgoing directory" );
965 err = TRUE;
966 }
967 break;
968 }
969 }
970
971 return err;
871 } 972 }
872 973
873 static Bool 974 static Bool
874 doPost( char *arg, const Cmd *cmd ) 975 doPost( char *arg, const Cmd *cmd )
875 { 976 {
876 Bool err, replyToFound, inHeader; 977 Bool err, replyToFound, dateFound, inHeader;
877 DynStr *s; 978 DynStr *s;
878 Str line, field, val, msgId, from, grp; 979 Str line, field, val, msgId, from;
879 const char* p; 980 const char* p;
981 ItemList * newsgroups, *control;
880 982
881 /* 983 /*
882 Get article and make following changes to the header: 984 Get article and make following changes to the header:
883 - add/replace/cut Message-ID depending on config options 985 - add/replace/cut Message-ID depending on config options
884 - add Reply-To with content of From, if missing 986 - add Reply-To with content of From, if missing
893 fflush( stdout ); 995 fflush( stdout );
894 Log_dbg( "[S FLUSH]" ); 996 Log_dbg( "[S FLUSH]" );
895 s = new_DynStr( 10000 ); 997 s = new_DynStr( 10000 );
896 msgId[ 0 ] = '\0'; 998 msgId[ 0 ] = '\0';
897 from[ 0 ] = '\0'; 999 from[ 0 ] = '\0';
898 grp[ 0 ] = '\0'; 1000 newsgroups = control = NULL;
899 replyToFound = FALSE; 1001 replyToFound = dateFound = FALSE;
900 inHeader = TRUE; 1002 inHeader = TRUE;
901 while ( getTxtLn( line, &err ) ) 1003 while ( getTxtLn( line, &err ) )
902 { 1004 {
903 if ( inHeader ) 1005 if ( inHeader )
904 { 1006 {
916 Log_dbg( "Replacing Message-ID with '%s'", msgId ); 1018 Log_dbg( "Replacing Message-ID with '%s'", msgId );
917 } 1019 }
918 else if ( msgId[ 0 ] == '\0' ) 1020 else if ( msgId[ 0 ] == '\0' )
919 { 1021 {
920 Prt_genMsgId( msgId, from, "NOFFLE" ); 1022 Prt_genMsgId( msgId, from, "NOFFLE" );
1023
921 Log_inf( "Adding missing Message-ID '%s'", msgId ); 1024 Log_inf( "Adding missing Message-ID '%s'", msgId );
922 } 1025 }
923 else if ( ! Prt_isValidMsgId( msgId ) ) 1026 else if ( ! Prt_isValidMsgId( msgId ) )
924 { 1027 {
925 Log_ntc( "Replacing invalid Message-ID with '%s'", 1028 Log_ntc( "Replacing invalid Message-ID with '%s'",
933 { 1036 {
934 Log_dbg( "Adding Reply-To field to posted message." ); 1037 Log_dbg( "Adding Reply-To field to posted message." );
935 DynStr_app( s, "Reply-To: " ); 1038 DynStr_app( s, "Reply-To: " );
936 DynStr_appLn( s, from ); 1039 DynStr_appLn( s, from );
937 } 1040 }
1041 if ( ! dateFound )
1042 {
1043 time_t t;
1044
1045 time( &t );
1046 strftime( val, MAXCHAR, "%d %b %Y %H:%M:%S %Z",
1047 localtime( &t ) );
1048 DynStr_app( s, "Date: " );
1049 DynStr_appLn( s, val );
1050 }
938 DynStr_appLn( s, p ); 1051 DynStr_appLn( s, p );
939 } 1052 }
940 else if ( Prt_getField( field, val, p ) ) 1053 else if ( Prt_getField( field, val, p ) )
941 { 1054 {
942 if ( strcmp( field, "message-id" ) == 0 ) 1055 if ( strcmp( field, "message-id" ) == 0 )
946 strcpy( from, val ); 1059 strcpy( from, val );
947 DynStr_appLn( s, p ); 1060 DynStr_appLn( s, p );
948 } 1061 }
949 else if ( strcmp( field, "newsgroups" ) == 0 ) 1062 else if ( strcmp( field, "newsgroups" ) == 0 )
950 { 1063 {
951 getFirstGrp( grp, val ); 1064 Utl_toLower( val );
952 Utl_toLower( grp ); 1065 newsgroups = new_Itl ( val, " ," );
1066 DynStr_appLn( s, p );
1067 }
1068 else if ( strcmp( field, "control" ) == 0 )
1069 {
1070 control = new_Itl ( val, " " );
953 DynStr_appLn( s, p ); 1071 DynStr_appLn( s, p );
954 } 1072 }
955 else if ( strcmp( field, "reply-to" ) == 0 ) 1073 else if ( strcmp( field, "reply-to" ) == 0 )
956 { 1074 {
957 replyToFound = TRUE; 1075 replyToFound = TRUE;
1076 DynStr_appLn( s, p );
1077 }
1078 else if ( strcmp( field, "date" ) == 0 )
1079 {
1080 dateFound = TRUE;
958 DynStr_appLn( s, p ); 1081 DynStr_appLn( s, p );
959 } 1082 }
960 else if ( strcmp( field, "x-sender" ) == 0 ) 1083 else if ( strcmp( field, "x-sender" ) == 0 )
961 { 1084 {
962 DynStr_app( s, "X-NOFFLE-X-Sender: " ); 1085 DynStr_app( s, "X-NOFFLE-X-Sender: " );
973 } 1096 }
974 if ( inHeader ) 1097 if ( inHeader )
975 Log_err( "Posted message has no body" ); 1098 Log_err( "Posted message has no body" );
976 if ( ! err ) 1099 if ( ! err )
977 { 1100 {
978 if ( grp[ 0 ] == '\0' ) 1101 if ( newsgroups == NULL || Itl_count( newsgroups ) == 0 )
979 { 1102 {
980 Log_err( "Posted message has no Newsgroups header field" ); 1103 Log_err( "Posted message has no valid Newsgroups header field" );
981 err = TRUE; 1104 err = TRUE;
982 } 1105 }
983 else if ( ! Grp_exists( grp ) ) 1106 else
984 { 1107 {
985 Log_err( "Unknown group in Newsgroups header field" ); 1108 const char *grp;
986 err = TRUE; 1109 Bool knownGrp = FALSE;
987 } 1110
988 else if ( ! Out_add( Grp_serv( grp ), msgId, s ) ) 1111 /* Check at least one group is known. */
989 { 1112 for( grp = Itl_first( newsgroups );
990 Log_err( "Cannot add posted article to outgoing directory" ); 1113 grp != NULL;
991 err = TRUE; 1114 grp = Itl_next( newsgroups ) )
992 } 1115 {
1116 if ( Grp_exists( grp ) )
1117 {
1118 knownGrp = TRUE;
1119 break;
1120 }
1121 }
1122
1123 if ( ! knownGrp )
1124 {
1125
1126 Log_err( "No known group in Newsgroups header field" );
1127 err = TRUE;
1128 }
1129 else
1130 {
1131 err = ( control == NULL )
1132 ? postArticle( newsgroups, msgId, s )
1133 : handleControl( control, newsgroups, msgId, s );
1134 }
1135 }
993 } 1136 }
994 if ( err ) 1137 if ( err )
995 putStat( STAT_POST_FAILED, "Posting failed" ); 1138 putStat( STAT_POST_FAILED, "Posting failed" );
996 else 1139 else
997 { 1140 {
998 putStat( STAT_POST_OK, "Message queued for posting" ); 1141 putStat( STAT_POST_OK, "Message queued for posting" );
999 if ( Online_true() ) 1142 if ( Online_true() )
1000 postArts(); 1143 postArts();
1001 } 1144 }
1145 del_Itl( newsgroups );
1146 del_Itl( control );
1002 del_DynStr( s ); 1147 del_DynStr( s );
1003 return TRUE; 1148 return TRUE;
1004 } 1149 }
1005 1150
1006 static void 1151 static void