comparison src/client.c @ 180:09ca6eb5c7ff noffle

[svn] * TODO,src/client.c,src/client.h,src/fetch.c,src/fetch.h,src/noffle.c: Improve error checking during fetches. A fetch is now aborted immediately if the connection times out or if an unexpected response arrives. This should fix problems with articles appearing in the wrong group, and possibly other mysterious happenings.
author bears
date Wed, 09 May 2001 12:33:43 +0100
parents 0ce333d046b9
children a43a528cfbe7
comparison
equal deleted inserted replaced
179:f973675760dc 180:09ca6eb5c7ff
1 /* 1 /*
2 client.c 2 client.c
3 3
4 $Id: client.c 269 2001-03-13 11:46:03Z enz $ 4 $Id: client.c 279 2001-05-09 11:33:43Z 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
164 return putCmdLn( line ); 164 return putCmdLn( line );
165 } 165 }
166 166
167 static int getStat( void ); 167 static int getStat( void );
168 168
169 static Bool 169 static int
170 performAuth( void ) 170 performAuth( void )
171 { 171 {
172 int stat; 172 int stat;
173 Str user, pass; 173 Str user, pass;
174 174
175 Cfg_authInfo( client.serv, user, pass ); 175 Cfg_authInfo( client.serv, user, pass );
176 if ( strcmp( user, "" ) == 0 ) 176 if ( strcmp( user, "" ) == 0 )
177 { 177 {
178 Log_err( "No username for authentication set" ); 178 Log_err( "No username for authentication set" );
179 return FALSE; 179 return STAT_AUTH_REQUIRED;
180 } 180 }
181 putCmd( "AUTHINFO USER %s", user ); 181 putCmd( "AUTHINFO USER %s", user );
182 stat = getStat(); 182 stat = getStat();
183 if ( stat == STAT_AUTH_ACCEPTED ) 183 if ( stat == STAT_AUTH_ACCEPTED )
184 return TRUE; 184 return stat;
185 else if ( stat != STAT_MORE_AUTH_REQUIRED ) 185 else if ( stat != STAT_MORE_AUTH_REQUIRED )
186 { 186 {
187 Log_err( "Username rejected. Server stat: %s", client.lastStat ); 187 Log_err( "Username rejected. Server stat: %s", client.lastStat );
188 return FALSE; 188 return stat;
189 } 189 }
190 if ( strcmp( pass, "" ) == 0 ) 190 if ( strcmp( pass, "" ) == 0 )
191 { 191 {
192 Log_err( "No password for authentication set" ); 192 Log_err( "No password for authentication set" );
193 return FALSE; 193 return STAT_AUTH_REQUIRED;
194 } 194 }
195 putCmd( "AUTHINFO PASS %s", pass ); 195 putCmd( "AUTHINFO PASS %s", pass );
196 stat = getStat(); 196 stat = getStat();
197 if ( stat != STAT_AUTH_ACCEPTED ) 197 if ( stat != STAT_AUTH_ACCEPTED )
198 {
199 Log_err( "Password rejected. Server status: %s", client.lastStat ); 198 Log_err( "Password rejected. Server status: %s", client.lastStat );
200 return FALSE; 199 return stat;
201 }
202 return TRUE;
203 } 200 }
204 201
205 static int 202 static int
206 getStat( void ) 203 getStat( void )
207 { 204 {
217 } 214 }
218 if ( result == STAT_AUTH_REQUIRED && ! client.auth ) 215 if ( result == STAT_AUTH_REQUIRED && ! client.auth )
219 { 216 {
220 client.auth = TRUE; 217 client.auth = TRUE;
221 strcpy( lastCmd, client.lastCmd ); 218 strcpy( lastCmd, client.lastCmd );
222 if ( performAuth() ) 219 result = performAuth();
220 if ( result == STAT_AUTH_ACCEPTED )
223 { 221 {
224 putCmd( lastCmd ); 222 putCmd( lastCmd );
225 return getStat(); 223 return getStat();
226 } 224 }
227 } 225 }
531 529
532 *noServerPattern = FALSE; 530 *noServerPattern = FALSE;
533 if ( ! putCmd( cmd ) ) 531 if ( ! putCmd( cmd ) )
534 return FALSE; 532 return FALSE;
535 stat = getStat(); 533 stat = getStat();
534 if ( stat == STAT_PROGRAM_FAULT )
535 return FALSE;
536
537 /*
538 * Try LIST instead of LIST ACTIVE in case server doesn't
539 * support LIST ACTIVE.
540 */
536 if ( pattern[ 0 ] != '\0' && stat != STAT_GRPS_FOLLOW ) 541 if ( pattern[ 0 ] != '\0' && stat != STAT_GRPS_FOLLOW )
537 { 542 {
538 *noServerPattern = TRUE; 543 *noServerPattern = TRUE;
539 if ( ! putCmd( "LIST" ) ) 544 if ( ! putCmd( "LIST" ) )
540 return FALSE; 545 return FALSE;
587 { 592 {
588 Str name, line, dsc, cmd; 593 Str name, line, dsc, cmd;
589 int stat; 594 int stat;
590 DynStr *response; 595 DynStr *response;
591 const char *lines; 596 const char *lines;
597 Bool result;
592 598
593 ASSERT( ! Lock_gotLock() ); 599 ASSERT( ! Lock_gotLock() );
594 Utl_cpyStr( cmd, "LIST NEWSGROUPS" ); 600 Utl_cpyStr( cmd, "LIST NEWSGROUPS" );
595 if ( pattern[ 0 ] != '\0' ) 601 if ( pattern[ 0 ] != '\0' )
596 { 602 {
600 606
601 *noServerPattern = FALSE; 607 *noServerPattern = FALSE;
602 if ( ! putCmd( cmd ) ) 608 if ( ! putCmd( cmd ) )
603 return FALSE; 609 return FALSE;
604 stat = getStat(); 610 stat = getStat();
611 if ( stat == STAT_PROGRAM_FAULT )
612 return FALSE;
613
614 /* Try without pattern in case server doesn't support patterns. */
605 if ( pattern[ 0 ] != '\0' && stat != STAT_GRPS_FOLLOW ) 615 if ( pattern[ 0 ] != '\0' && stat != STAT_GRPS_FOLLOW )
606 { 616 {
607 *noServerPattern = TRUE; 617 *noServerPattern = TRUE;
608 if ( !putCmd( "LIST NEWSGROUPS" ) ) 618 if ( !putCmd( "LIST NEWSGROUPS" ) )
609 return FALSE; 619 return FALSE;
621 631
622 if ( ! Lock_openDatabases() ) 632 if ( ! Lock_openDatabases() )
623 return FALSE; 633 return FALSE;
624 634
625 lines = DynStr_str( response ); 635 lines = DynStr_str( response );
636 result = TRUE;
626 while ( ( lines = Utl_getLn( line, lines) ) != NULL ) 637 while ( ( lines = Utl_getLn( line, lines) ) != NULL )
627 { 638 {
628 if ( sscanf( line, "%s", name ) != 1 ) 639 if ( sscanf( line, "%s", name ) != 1 )
629 { 640 {
630 Log_err( "Unknown reply to LIST NEWSGROUPS: %s", line ); 641 Log_err( "Unknown reply to LIST NEWSGROUPS: %s", line );
631 continue; 642 result = FALSE;
643 break;
632 } 644 }
633 if ( *noServerPattern && ! isGetGroup( name ) ) 645 if ( *noServerPattern && ! isGetGroup( name ) )
634 continue; 646 continue;
635 strcpy( dsc, Utl_restOfLn( line, 1 ) ); 647 strcpy( dsc, Utl_restOfLn( line, 1 ) );
636 if ( Grp_exists( name ) ) 648 if ( Grp_exists( name ) )
639 Grp_setDsc( name, dsc ); 651 Grp_setDsc( name, dsc );
640 } 652 }
641 } 653 }
642 Lock_closeDatabases(); 654 Lock_closeDatabases();
643 del_DynStr( response ); 655 del_DynStr( response );
644 return TRUE; 656 return result;
645 } 657 }
646 658
647 Bool 659 Bool
648 Client_getDsc( void ) 660 Client_getDsc( void )
649 { 661 {
662 doneOne = TRUE; 674 doneOne = TRUE;
663 if ( noServerPattern ) 675 if ( noServerPattern )
664 break; 676 break;
665 } 677 }
666 678
667 if ( ! doneOne ) 679 if ( res && ! doneOne )
668 res = doGetDsc( "", &noServerPattern ); 680 res = doGetDsc( "", &noServerPattern );
669 681
670 del_GrEn( ge ); 682 del_GrEn( ge );
671 return res; 683 return res;
672 } 684 }
907 919
908 Log_dbg( "Requesting Newsgroups headers for remote %lu-%lu", 920 Log_dbg( "Requesting Newsgroups headers for remote %lu-%lu",
909 rmtFirst, rmtLast ); 921 rmtFirst, rmtLast );
910 922
911 newsgroups = collectTxt(); 923 newsgroups = collectTxt();
924 if ( newsgroups == NULL )
925 return FALSE;
926
912 groupLines = DynStr_str( newsgroups ); 927 groupLines = DynStr_str( newsgroups );
913 } 928 }
914 else 929 else
915 { 930 {
916 groupLines = NULL; 931 groupLines = NULL;
1061 else 1076 else
1062 retrievingFailed( msgId, "Connection broke down" ); 1077 retrievingFailed( msgId, "Connection broke down" );
1063 return ! err; 1078 return ! err;
1064 } 1079 }
1065 1080
1066 void 1081 Bool
1067 Client_retrieveArt( const char *msgId ) 1082 Client_retrieveArt( const char *msgId )
1068 { 1083 {
1084 Bool res = FALSE;
1085
1069 ASSERT( Lock_gotLock() ); 1086 ASSERT( Lock_gotLock() );
1070 if ( ! Db_contains( msgId ) ) 1087 if ( ! Db_contains( msgId ) )
1071 { 1088 {
1072 Log_err( "Article '%s' not prepared in database. Skipping.", msgId ); 1089 Log_err( "Article '%s' not prepared in database. Skipping.", msgId );
1073 return; 1090 return TRUE;
1074 } 1091 }
1075 if ( ! ( Db_status( msgId ) & DB_NOT_DOWNLOADED ) ) 1092 if ( ! ( Db_status( msgId ) & DB_NOT_DOWNLOADED ) )
1076 { 1093 {
1077 Log_inf( "Article '%s' already retrieved. Skipping.", msgId ); 1094 Log_inf( "Article '%s' already retrieved. Skipping.", msgId );
1078 return; 1095 return TRUE;
1079 } 1096 }
1080 1097
1081 Lock_closeDatabases(); 1098 Lock_closeDatabases();
1082 if ( ! putCmd( "ARTICLE %s", msgId ) ) 1099 if ( ! putCmd( "ARTICLE %s", msgId ) )
1083 retrievingFailed( msgId, "Connection broke down" ); 1100 retrievingFailed( msgId, "Connection broke down" );
1084 else if ( getStat() != STAT_ART_FOLLOWS ) 1101 else if ( getStat() != STAT_ART_FOLLOWS )
1085 retrievingFailed( msgId, client.lastStat ); 1102 retrievingFailed( msgId, client.lastStat );
1086 else 1103 else
1087 retrieveAndStoreArt( msgId, 0, 0 ); 1104 res = retrieveAndStoreArt( msgId, 0, 0 );
1088 Lock_openDatabases(); 1105 Lock_openDatabases();
1089 } 1106 return res;
1090 1107 }
1091 void 1108
1109 Bool
1092 Client_retrieveArtList( const char *list, int *artcnt, int artmax ) 1110 Client_retrieveArtList( const char *list, int *artcnt, int artmax )
1093 { 1111 {
1094 Str msgId; 1112 Str msgId;
1095 DynStr *s; 1113 DynStr *s;
1096 const char *p; 1114 const char *p;
1115 Bool res;
1097 1116
1098 ASSERT( Lock_gotLock() ); 1117 ASSERT( Lock_gotLock() );
1099 Log_inf( "Retrieving article list" ); 1118 Log_inf( "Retrieving article list" );
1100 s = new_DynStr( (int)strlen( list ) ); 1119 s = new_DynStr( (int)strlen( list ) );
1101 p = list; 1120 p = list;
1107 Log_inf( "[%d/%d] Skipping %s (already retrieved)", ++(*artcnt), artmax, msgId ); 1126 Log_inf( "[%d/%d] Skipping %s (already retrieved)", ++(*artcnt), artmax, msgId );
1108 else if ( ! putCmdNoFlush( "ARTICLE %s", msgId ) ) 1127 else if ( ! putCmdNoFlush( "ARTICLE %s", msgId ) )
1109 { 1128 {
1110 retrievingFailed( msgId, "Connection broke down" ); 1129 retrievingFailed( msgId, "Connection broke down" );
1111 del_DynStr( s ); 1130 del_DynStr( s );
1112 return; 1131 return FALSE;
1113 } 1132 }
1114 else 1133 else
1115 DynStr_appLn( s, msgId ); 1134 DynStr_appLn( s, msgId );
1116 1135
1117 Lock_closeDatabases(); 1136 Lock_closeDatabases();
1118 fflush( client.out ); 1137 fflush( client.out );
1119 Log_dbg( "[S FLUSH]" ); 1138 Log_dbg( "[S FLUSH]" );
1120 1139
1121 p = DynStr_str( s ); 1140 p = DynStr_str( s );
1122 while ( ( p = Utl_getLn( msgId, p ) ) ) 1141 res = TRUE;
1142 while ( res && ( p = Utl_getLn( msgId, p ) ) )
1123 { 1143 {
1124 if ( getStat() != STAT_ART_FOLLOWS ) 1144 if ( getStat() != STAT_ART_FOLLOWS )
1145 {
1125 retrievingFailed( msgId, client.lastStat ); 1146 retrievingFailed( msgId, client.lastStat );
1126 else if ( ! retrieveAndStoreArt( msgId, ++(*artcnt), artmax ) ) 1147 res = FALSE;
1127 break; 1148 }
1149 else
1150 res = retrieveAndStoreArt( msgId, ++(*artcnt), artmax );
1128 } 1151 }
1129 del_DynStr( s ); 1152 del_DynStr( s );
1130 Lock_openDatabases(); 1153 Lock_openDatabases();
1154 return res;
1131 } 1155 }
1132 1156
1133 Bool 1157 Bool
1134 Client_changeToGrp( const char* name ) 1158 Client_changeToGrp( const char* name )
1135 { 1159 {
1164 *first = client.rmtFirst; 1188 *first = client.rmtFirst;
1165 *last = client.rmtLast; 1189 *last = client.rmtLast;
1166 } 1190 }
1167 1191
1168 Bool 1192 Bool
1169 Client_postArt( const char *msgId, const char *artTxt, 1193 Client_postArt( const char *msgId, const char *artTxt, Str errStr )
1170 Str errStr ) 1194 {
1171 { 1195 int stat;
1196
1197 errStr[0] = '\0';
1198
1172 if ( ! putCmd( "POST" ) ) 1199 if ( ! putCmd( "POST" ) )
1173 return FALSE; 1200 return FALSE;
1174 if ( getStat() != STAT_SEND_ART ) 1201 stat = getStat();
1202 if ( stat == STAT_PROGRAM_FAULT )
1203 return FALSE;
1204 else if ( stat != STAT_SEND_ART )
1175 { 1205 {
1176 Log_err( "Posting of %s not allowed: %s", msgId, client.lastStat ); 1206 Log_err( "Posting of %s not allowed: %s", msgId, client.lastStat );
1177 strcpy( errStr, client.lastStat ); 1207 strcpy( errStr, client.lastStat );
1178 return FALSE; 1208 return TRUE;
1179 } 1209 }
1180 putTxtBuf( artTxt ); 1210 putTxtBuf( artTxt );
1181 putEndOfTxt(); 1211 putEndOfTxt();
1182 if ( getStat() != STAT_POST_OK ) 1212 stat = getStat();
1213 if ( stat == STAT_PROGRAM_FAULT )
1214 return FALSE;
1215 else if ( stat != STAT_POST_OK )
1183 { 1216 {
1184 Log_err( "Posting of %s failed: %s", msgId, client.lastStat ); 1217 Log_err( "Posting of %s failed: %s", msgId, client.lastStat );
1185 strcpy( errStr, client.lastStat ); 1218 strcpy( errStr, client.lastStat );
1186 return FALSE; 1219 return TRUE;
1187 } 1220 }
1188 Log_inf( "Posted %s (Status: %s)", msgId, client.lastStat ); 1221 Log_inf( "Posted %s (Status: %s)", msgId, client.lastStat );
1189 return TRUE; 1222 return TRUE;
1190 } 1223 }