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