comparison src/server.c @ 88:1fcdced0246e noffle

[svn] Move posting code to post.c, add command line posting
author bears
date Thu, 18 May 2000 13:17:23 +0100
parents dfcb28566d36
children 46062d2f9d20
comparison
equal deleted inserted replaced
87:bf8c97460fd7 88:1fcdced0246e
1 /* 1 /*
2 server.c 2 server.c
3 3
4 $Id: server.c 96 2000-05-17 10:51:22Z enz $ 4 $Id: server.c 100 2000-05-18 12:17:23Z 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
29 #include <unistd.h> 29 #include <unistd.h>
30 #include "client.h" 30 #include "client.h"
31 #include "common.h" 31 #include "common.h"
32 #include "configfile.h" 32 #include "configfile.h"
33 #include "content.h" 33 #include "content.h"
34 #include "control.h"
35 #include "database.h" 34 #include "database.h"
36 #include "dynamicstring.h" 35 #include "dynamicstring.h"
37 #include "fetch.h" 36 #include "fetch.h"
38 #include "fetchlist.h" 37 #include "fetchlist.h"
39 #include "group.h" 38 #include "group.h"
40 #include "itemlist.h" 39 #include "itemlist.h"
41 #include "lock.h" 40 #include "lock.h"
42 #include "log.h" 41 #include "log.h"
43 #include "online.h" 42 #include "online.h"
44 #include "outgoing.h"
45 #include "over.h" 43 #include "over.h"
46 #include "post.h" 44 #include "post.h"
47 #include "protocol.h" 45 #include "protocol.h"
48 #include "pseudo.h" 46 #include "pseudo.h"
49 #include "request.h" 47 #include "request.h"
957 } 955 }
958 } 956 }
959 return TRUE; 957 return TRUE;
960 } 958 }
961 959
962 /* Cancel and return TRUE if need to send cancel message on to server. */ 960 static Bool
963 static Bool 961 doPost( char *arg, const Cmd *cmd )
964 controlCancel( const char *cancelId ) 962 {
965 { 963 DynStr *s;
966 return ( Ctrl_cancel( cancelId ) == CANCEL_NEEDS_MSG ); 964 Str line;
967 }
968
969 /*
970 It's a control message. Currently we only know about 'cancel'
971 messages; others are passed on for outside groups, and logged
972 as ignored for local groups.
973 */
974 static Bool
975 handleControl( ItemList *control, ItemList *newsgroups,
976 const char *msgId, const DynStr *art )
977 {
978 const char *grp;
979 const char *op;
980 Bool err = FALSE;
981 Bool localDone = FALSE;
982
983 op = Itl_first( control );
984 if ( op == NULL )
985 {
986 Log_err( "Malformed control line." );
987 return TRUE;
988 }
989 else if ( strcasecmp( op, "cancel" ) == 0 )
990 {
991 if ( controlCancel( Itl_next( control ) ) )
992 localDone = TRUE;
993 else
994 return err;
995 }
996
997 /* Pass on for outside groups. */
998 for( grp = Itl_first( newsgroups );
999 grp != NULL;
1000 grp = Itl_next( newsgroups ) )
1001 {
1002 if ( Grp_exists( grp ) && ! Grp_local( grp ) )
1003 {
1004 if ( ! Out_add( Grp_server( grp ), msgId, art ) )
1005 {
1006 Log_err( "Cannot add posted article to outgoing directory" );
1007 err = TRUE;
1008 }
1009 break;
1010 }
1011 }
1012
1013 if ( localDone )
1014 return err;
1015
1016 /* Log 'can't do' for internal groups. */
1017 for( grp = Itl_first( newsgroups );
1018 grp != NULL;
1019 grp = Itl_next( newsgroups ) )
1020 {
1021 if ( Grp_exists( grp ) && Grp_local( grp ) )
1022 Log_inf( "Ignoring control '%s' for '%s'.", op, grp );
1023 }
1024
1025 return err;
1026 }
1027
1028 static Bool
1029 postArticle( ItemList *newsgroups, const char *msgId, const DynStr *art )
1030 {
1031 const char *grp;
1032 Bool err; 965 Bool err;
1033 Bool oneLocal;
1034
1035 err = oneLocal = FALSE;
1036
1037 /* Run round first doing all local groups. */
1038 for( grp = Itl_first( newsgroups );
1039 grp != NULL;
1040 grp = Itl_next( newsgroups ) )
1041 {
1042 if ( Grp_local( grp ) )
1043 {
1044 if ( ! oneLocal )
1045 {
1046 if ( ! Post_open( DynStr_str( art ) ) )
1047 {
1048 err = TRUE;
1049 break;
1050 }
1051 else
1052 oneLocal = TRUE;
1053 }
1054
1055 if ( ! Post_add( grp ) )
1056 err = TRUE;
1057 }
1058 }
1059 if ( oneLocal )
1060 Post_close();
1061
1062 /* Now look for a valid external group. */
1063 for( grp = Itl_first( newsgroups );
1064 grp != NULL;
1065 grp = Itl_next( newsgroups ) )
1066 {
1067 if ( Grp_exists( grp ) && ! Grp_local( grp ) )
1068 {
1069 if ( ! Out_add( Grp_server( grp ), msgId, art ) )
1070 {
1071 Log_err( "Cannot add posted article to outgoing directory" );
1072 err = TRUE;
1073 }
1074 break;
1075 }
1076 }
1077
1078 return err;
1079 }
1080
1081 static Bool
1082 doPost( char *arg, const Cmd *cmd )
1083 {
1084 Bool err, replyToFound, dateFound, inHeader;
1085 DynStr *s;
1086 Str line, field, val, msgId, from;
1087 const char* p;
1088 ItemList * newsgroups, *control;
1089 966
1090 UNUSED(arg); 967 UNUSED(arg);
1091 UNUSED(cmd); 968 UNUSED(cmd);
1092 969
1093 /*
1094 Get article and make following changes to the header:
1095 - add/replace/cut Message-ID depending on config options
1096 - add Reply-To with content of From, if missing
1097 (some providers overwrite From field)
1098 - rename X-Sender header to X-NOFFLE-X-Sender
1099 (some providers want to insert their own X-Sender)
1100
1101 For doing this, it is not necessary to parse multiple-line
1102 headers.
1103 */
1104 putStat( STAT_SEND_ART, "Continue (end with period)" ); 970 putStat( STAT_SEND_ART, "Continue (end with period)" );
1105 fflush( stdout ); 971 fflush( stdout );
1106 Log_dbg( "[S FLUSH]" ); 972 Log_dbg( "[S FLUSH]" );
1107 s = new_DynStr( 10000 ); 973 s = new_DynStr( 10000 );
1108 msgId[ 0 ] = '\0'; 974 err = FALSE;
1109 from[ 0 ] = '\0'; 975 while ( ! err && getTxtLn( line, &err ) )
1110 newsgroups = control = NULL; 976 DynStr_appLn( s, line );
1111 replyToFound = dateFound = FALSE; 977
1112 inHeader = TRUE; 978 if ( ! err
1113 while ( getTxtLn( line, &err ) ) 979 && Post_open( DynStr_str( s ) )
1114 { 980 && Post_post( FALSE ) )
1115 if ( inHeader )
1116 {
1117 p = Utl_stripWhiteSpace( line );
1118 if ( *p == '\0' )
1119 {
1120 inHeader = FALSE;
1121 if ( from[ 0 ] == '\0' )
1122 Log_err( "Posted message has no From field" );
1123 if ( Cfg_replaceMsgId() )
1124 {
1125 Prt_genMsgId( msgId, from, "NOFFLE" );
1126 Log_dbg( "Replacing Message-ID with '%s'", msgId );
1127 }
1128 else if ( msgId[ 0 ] == '\0' )
1129 {
1130 Prt_genMsgId( msgId, from, "NOFFLE" );
1131
1132 Log_inf( "Adding missing Message-ID '%s'", msgId );
1133 }
1134 else if ( ! Prt_isValidMsgId( msgId ) )
1135 {
1136 Log_ntc( "Replacing invalid Message-ID with '%s'",
1137 msgId );
1138 Prt_genMsgId( msgId, from, "NOFFLE" );
1139 }
1140 DynStr_app( s, "Message-ID: " );
1141 DynStr_appLn( s, msgId );
1142 if ( ! replyToFound && from[ 0 ] != '\0' )
1143 {
1144 Log_dbg( "Adding Reply-To field to posted message." );
1145 DynStr_app( s, "Reply-To: " );
1146 DynStr_appLn( s, from );
1147 }
1148 if ( ! dateFound )
1149 {
1150 time_t t;
1151
1152 time( &t );
1153 Utl_rfc822Date( t, val );
1154 DynStr_app( s, "Date: " );
1155 DynStr_appLn( s, val );
1156 }
1157 DynStr_appLn( s, p );
1158 }
1159 else if ( Prt_getField( field, val, p ) )
1160 {
1161 if ( strcmp( field, "message-id" ) == 0 )
1162 strcpy( msgId, val );
1163 else if ( strcmp( field, "from" ) == 0 )
1164 {
1165 strcpy( from, val );
1166 DynStr_appLn( s, p );
1167 }
1168 else if ( strcmp( field, "newsgroups" ) == 0 )
1169 {
1170 Utl_toLower( val );
1171 newsgroups = new_Itl ( val, " ," );
1172 DynStr_appLn( s, p );
1173 }
1174 else if ( strcmp( field, "control" ) == 0 )
1175 {
1176 control = new_Itl ( val, " " );
1177 DynStr_appLn( s, p );
1178 }
1179 else if ( strcmp( field, "reply-to" ) == 0 )
1180 {
1181 replyToFound = TRUE;
1182 DynStr_appLn( s, p );
1183 }
1184 else if ( strcmp( field, "date" ) == 0 )
1185 {
1186 dateFound = TRUE;
1187 DynStr_appLn( s, p );
1188 }
1189 else if ( strcmp( field, "x-sender" ) == 0 )
1190 {
1191 DynStr_app( s, "X-NOFFLE-X-Sender: " );
1192 DynStr_appLn( s, val );
1193 }
1194 else
1195 DynStr_appLn( s, p );
1196 }
1197 else
1198 DynStr_appLn( s, line );
1199 }
1200 else
1201 DynStr_appLn( s, line );
1202 }
1203 if ( inHeader )
1204 Log_err( "Posted message has no body" );
1205 if ( ! err )
1206 {
1207 if ( newsgroups == NULL || Itl_count( newsgroups ) == 0 )
1208 {
1209 Log_err( "Posted message has no valid Newsgroups header field" );
1210 err = TRUE;
1211 }
1212 else
1213 {
1214 const char *grp;
1215 Bool knownGrp = FALSE;
1216 Bool postAllowedGrp = FALSE;
1217
1218 /* Check at least one group is known. */
1219 for( grp = Itl_first( newsgroups );
1220 grp != NULL;
1221 grp = Itl_next( newsgroups ) )
1222 {
1223 if ( Grp_exists( grp ) )
1224 {
1225 knownGrp = TRUE;
1226 switch( Grp_postAllow( grp ) )
1227 {
1228 case 'n':
1229 break;
1230 case 'm':
1231 /* Can't post to moderated local groups. */
1232 postAllowedGrp = ! Grp_local( grp );
1233 break;
1234 default:
1235 postAllowedGrp = TRUE;
1236 }
1237 if ( postAllowedGrp )
1238 break;
1239 }
1240 }
1241
1242 if ( ! knownGrp )
1243 {
1244
1245 Log_err( "No known group in Newsgroups header field" );
1246 err = TRUE;
1247 }
1248 else if ( ! postAllowedGrp )
1249 {
1250
1251 Log_err( "No group permits posting" );
1252 err = TRUE;
1253 }
1254 else
1255 {
1256 err = ( control == NULL )
1257 ? postArticle( newsgroups, msgId, s )
1258 : handleControl( control, newsgroups, msgId, s );
1259 }
1260 }
1261 }
1262 if ( err )
1263 putStat( STAT_POST_FAILED, "Posting failed" );
1264 else
1265 { 981 {
1266 putStat( STAT_POST_OK, "Message posted" ); 982 putStat( STAT_POST_OK, "Message posted" );
1267 if ( Online_true() ) 983 if ( Online_true() )
1268 postArts(); 984 postArts();
1269 } 985 }
1270 del_Itl( newsgroups ); 986 else
1271 del_Itl( control ); 987 putStat( STAT_POST_FAILED, "Posting failed" );
988 Post_close();
1272 del_DynStr( s ); 989 del_DynStr( s );
1273 return TRUE; 990 return TRUE;
1274 } 991 }
1275 992
1276 static void 993 static void