comparison src/fetch.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 22b81617d427
children 9854ea5f295f
comparison
equal deleted inserted replaced
179:f973675760dc 180:09ca6eb5c7ff
1 /* 1 /*
2 fetch.c 2 fetch.c
3 3
4 $Id: fetch.c 236 2000-12-05 19:50:09Z enz $ 4 $Id: fetch.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
57 return FALSE; 57 return FALSE;
58 } 58 }
59 return TRUE; 59 return TRUE;
60 } 60 }
61 61
62 void 62 Bool
63 Fetch_getNewGrps( void ) 63 Fetch_getNewGrps( void )
64 { 64 {
65 time_t t; 65 time_t t;
66 Str file; 66 Str file;
67 67
69 snprintf( file, MAXCHAR, "%s/lastupdate.%s", 69 snprintf( file, MAXCHAR, "%s/lastupdate.%s",
70 Cfg_spoolDir(), fetch.serv ); 70 Cfg_spoolDir(), fetch.serv );
71 if ( ! Utl_getStamp( &t, file ) ) 71 if ( ! Utl_getStamp( &t, file ) )
72 { 72 {
73 Log_err( "Cannot read %s. Please run noffle --query groups", file ); 73 Log_err( "Cannot read %s. Please run noffle --query groups", file );
74 return; 74 return FALSE;
75 } 75 }
76 Log_inf( "Updating groupinfo" ); 76 Log_inf( "Updating groupinfo" );
77 Client_getNewgrps( &t ); 77 return Client_getNewgrps( &t );
78 } 78 }
79 79
80 /* Databases open on entry, closed on exit. */ 80 /* Databases open on entry, closed on exit. */
81 static void 81 static Bool
82 fetchNewArts( const char *name, FetchMode mode ) 82 fetchNewArts( const char *name, FetchMode mode )
83 { 83 {
84 int next, first, last, refetch; 84 int next, first, last, refetch;
85 85
86 if ( ! Client_changeToGrp( name ) ) 86 if ( ! Client_changeToGrp( name ) )
87 { 87 {
88 Log_err( "Could not change to group %s", name ); 88 Log_err( "Could not change to group %s", name );
89 if ( Lock_gotLock() ) 89 if ( Lock_gotLock() )
90 Lock_closeDatabases(); 90 Lock_closeDatabases();
91 return; 91 return FALSE;
92 } 92 }
93 Client_rmtFirstLast( &first, &last ); 93 Client_rmtFirstLast( &first, &last );
94 Cont_read( name ); 94 Cont_read( name );
95 next = Grp_rmtNext( name ); 95 next = Grp_rmtNext( name );
96 if ( next == GRP_RMT_NEXT_NOT_SUBSCRIBED ) 96 if ( next == GRP_RMT_NEXT_NOT_SUBSCRIBED )
99 { 99 {
100 Log_inf( "No new articles in %s", name ); 100 Log_inf( "No new articles in %s", name );
101 Cont_write(); 101 Cont_write();
102 Grp_setFirstLast( name, Cont_first(), Cont_last() ); 102 Grp_setFirstLast( name, Cont_first(), Cont_last() );
103 Lock_closeDatabases(); 103 Lock_closeDatabases();
104 return; 104 return TRUE;
105 } 105 }
106 if ( first == 0 && last == 0 ) 106 if ( first == 0 && last == 0 )
107 { 107 {
108 Log_inf( "No articles in %s", name ); 108 Log_inf( "No articles in %s", name );
109 Cont_write(); 109 Cont_write();
110 Grp_setFirstLast( name, Cont_first(), Cont_last() ); 110 Grp_setFirstLast( name, Cont_first(), Cont_last() );
111 Lock_closeDatabases(); 111 Lock_closeDatabases();
112 return; 112 return TRUE;
113 } 113 }
114 if ( next > last + 1 ) 114 if ( next > last + 1 )
115 { 115 {
116 refetch = last - Cfg_maxFetch() + 1; 116 refetch = last - Cfg_maxFetch() + 1;
117 if ( refetch < 0 ) refetch = 1; 117 if ( refetch < 0 ) refetch = 1;
134 first = last - Cfg_maxFetch() + 1; 134 first = last - Cfg_maxFetch() + 1;
135 } 135 }
136 Log_inf( "Getting remote overviews %lu-%lu for group %s", 136 Log_inf( "Getting remote overviews %lu-%lu for group %s",
137 first, last, name ); 137 first, last, name );
138 Lock_closeDatabases(); 138 Lock_closeDatabases();
139 Client_getOver( name, first, last, mode ); 139 return Client_getOver( name, first, last, mode );
140 } 140 }
141 141
142 void 142 Bool
143 Fetch_getNewArts( const char *name, FetchMode mode ) 143 Fetch_getNewArts( const char *name, FetchMode mode )
144 { 144 {
145 if ( ! Lock_openDatabases() ) 145 if ( ! Lock_openDatabases() )
146 { 146 {
147 Log_err( "Could not open message base" ); 147 Log_err( "Could not open message base" );
148 return; 148 return FALSE;
149 } 149 }
150 fetchNewArts( name, mode ); 150 return fetchNewArts( name, mode );
151 } 151 }
152 152
153 void 153 Bool
154 Fetch_updateGrps( void ) 154 Fetch_updateGrps( void )
155 { 155 {
156 FetchMode mode; 156 FetchMode mode;
157 int i, size; 157 int i, size;
158 const char *name; 158 const char *name;
159 159
160 ASSERT( fetch.ready ); 160 ASSERT( fetch.ready );
161 if ( ! Lock_openDatabases() ) 161 if ( ! Lock_openDatabases() )
162 { 162 {
163 Log_err( "Could not open message base" ); 163 Log_err( "Could not open message base" );
164 return; 164 return FALSE;
165 } 165 }
166 Fetchlist_read(); 166 Fetchlist_read();
167 size = Fetchlist_size(); 167 size = Fetchlist_size();
168 for ( i = 0; i < size; ++i ) 168 for ( i = 0; i < size; ++i )
169 { 169 {
170 Fetchlist_element( &name, &mode, i ); 170 Fetchlist_element( &name, &mode, i );
171 if ( strcmp( Grp_server( name ), fetch.serv ) == 0 ) 171 if ( strcmp( Grp_server( name ), fetch.serv ) == 0 )
172 { 172 {
173 fetchNewArts( name, mode ); 173 if ( ! fetchNewArts( name, mode ) )
174 return FALSE;
174 if ( ! Lock_openDatabases() ) 175 if ( ! Lock_openDatabases() )
175 { 176 {
176 Log_err( "Could not open message base" ); 177 Log_err( "Could not open message base" );
177 return; 178 return FALSE;
178 } 179 }
179 } 180 }
180 } 181 }
181 Lock_closeDatabases(); 182 Lock_closeDatabases();
182 } 183 return TRUE;
183 184 }
184 static void 185
186 static Bool
185 fetchMessageList( const char *list, int *artcnt, int artmax ) 187 fetchMessageList( const char *list, int *artcnt, int artmax )
186 { 188 {
187 const char *p; 189 const char *p;
188 Str msgId; 190 Str msgId;
189 191
190 ASSERT( Lock_gotLock() ); 192 ASSERT( Lock_gotLock() );
191 Client_retrieveArtList( list, artcnt, artmax ); 193 if ( ! Client_retrieveArtList( list, artcnt, artmax ) )
194 return FALSE;
192 p = list; 195 p = list;
193 while ( ( p = Utl_getLn( msgId, p ) ) ) 196 while ( ( p = Utl_getLn( msgId, p ) ) )
194 Req_remove( fetch.serv, msgId ); 197 Req_remove( fetch.serv, msgId );
195 } 198 return TRUE;
196 199 }
197 void 200
201 Bool
198 Fetch_getReq_( void ) 202 Fetch_getReq_( void )
199 { 203 {
200 Str msgId; 204 Str msgId;
201 DynStr *list; 205 DynStr *list;
202 DynStr *fetchList; 206 DynStr *fetchList;
203 const char *p; 207 const char *p;
204 int count = 0, artcnt = 0, artmax = 0; 208 int count = 0, artcnt = 0, artmax = 0;
209 Bool res;
205 210
206 ASSERT( fetch.ready ); 211 ASSERT( fetch.ready );
207 Log_dbg( "Retrieving articles marked for download" ); 212 Log_dbg( "Retrieving articles marked for download" );
208 list = new_DynStr( 10000 ); 213 list = new_DynStr( 10000 );
209 fetchList = new_DynStr( 1000 ); 214 fetchList = new_DynStr( 1000 );
210 if ( list == NULL || fetchList == NULL ) 215 if ( list == NULL || fetchList == NULL )
211 { 216 {
212 if ( list != NULL ) 217 if ( list != NULL )
213 del_DynStr( list ); 218 del_DynStr( list );
214 Log_err( "Out of memory in Fetch_get_Req_"); 219 Log_err( "Out of memory in Fetch_get_Req_");
215 return; 220 return FALSE;
216 } 221 }
217 222
218 /* 223 /*
219 * Get all waiting message IDs for this server. We copy into a master 224 * Get all waiting message IDs for this server. We copy into a master
220 * list as the requests file will be closed and re-opened during the 225 * list as the requests file will be closed and re-opened during the
221 * fetch and the position therein will be lost. 226 * fetch and the position therein will be lost.
222 */ 227 */
223 if ( ! Lock_openDatabases() ) 228 if ( ! Lock_openDatabases() )
224 { 229 {
225 Log_err( "Could not open message base" ); 230 Log_err( "Could not open message base" );
226 return; 231 return FALSE;
227 } 232 }
228 233
229 if ( Req_first( fetch.serv, msgId ) ) 234 if ( Req_first( fetch.serv, msgId ) )
230 { 235 {
231 do 236 do
237 Log_inf( "%d TOTAL messages to download", artmax); 242 Log_inf( "%d TOTAL messages to download", artmax);
238 } 243 }
239 244
240 /* Retrieve in groups of up to size MAX_ARTICLE_CMDS_QUEUED. */ 245 /* Retrieve in groups of up to size MAX_ARTICLE_CMDS_QUEUED. */
241 p = DynStr_str( list ); 246 p = DynStr_str( list );
242 while ( ( p = Utl_getLn( msgId, p ) ) != NULL ) 247 res = TRUE;
248 while ( res && ( p = Utl_getLn( msgId, p ) ) != NULL )
243 { 249 {
244 DynStr_appLn( fetchList, msgId ); 250 DynStr_appLn( fetchList, msgId );
245 if ( ++count % MAX_ARTICLE_CMDS_QUEUED == 0 ) 251 if ( ++count % MAX_ARTICLE_CMDS_QUEUED == 0 )
246 { 252 {
247 fetchMessageList( DynStr_str( fetchList ), &artcnt, artmax ); 253 res = fetchMessageList( DynStr_str( fetchList ), &artcnt, artmax );
248 DynStr_clear( fetchList ); 254 DynStr_clear( fetchList );
249 } 255 }
250 } 256 }
251 fetchMessageList( DynStr_str( fetchList ), &artcnt, artmax ); 257 res = res && fetchMessageList( DynStr_str( fetchList ), &artcnt, artmax );
252 258
253 del_DynStr( fetchList ); 259 del_DynStr( fetchList );
254 del_DynStr( list ); 260 del_DynStr( list );
255 Lock_closeDatabases(); 261 Lock_closeDatabases();
262 return res;
256 } 263 }
257 264
258 static void 265 static void
259 returnArticleToSender( const char *sender, const char *reason, 266 returnArticleToSender( const char *sender, const char *reason,
260 const char *article ) 267 const char *article )
294 Log_err( "'%s' exit value %d", cmd, ret ); 301 Log_err( "'%s' exit value %d", cmd, ret );
295 signal( SIGPIPE, lastHandler ); 302 signal( SIGPIPE, lastHandler );
296 } 303 }
297 } 304 }
298 305
299 void 306 Bool
300 Fetch_postArts( void ) 307 Fetch_postArts( void )
301 { 308 {
302 DynStr *s; 309 DynStr *s;
303 Str msgId, errStr, sender; 310 Str msgId, errStr, sender;
304 const char *txt; 311 const char *txt;
305 312 Bool res;
313
314 res = TRUE;
306 s = new_DynStr( 10000 ); 315 s = new_DynStr( 10000 );
307 if ( Out_first( fetch.serv, msgId, s ) ) 316 if ( Out_first( fetch.serv, msgId, s ) )
308 { 317 {
309 Log_inf( "Posting articles" ); 318 Log_inf( "Posting articles" );
310 do 319 do
311 { 320 {
312 txt = DynStr_str( s ); 321 txt = DynStr_str( s );
313 Out_remove( fetch.serv, msgId ); 322 if ( ! Client_postArt( msgId, txt, errStr ) )
314 if ( ! Client_postArt( msgId, txt, errStr ) ) 323 {
315 { 324 res = FALSE;
316 Utl_cpyStr( sender, Cfg_mailTo() ); 325 break;
317 if ( strcmp( sender, "" ) == 0 326 }
318 && ! Prt_searchHeader( txt, "SENDER", sender ) 327
319 && ! Prt_searchHeader( txt, "X-NOFFLE-X-SENDER", 328 /*
320 sender ) /* see server.c */ 329 * OK, no server communication SNAFU during post. Now, do we
321 && ! Prt_searchHeader( txt, "FROM", sender ) ) 330 * get an error response? If so, try to return article to sender.
322 Log_err( "Article %s has no From/Sender/X-Sender field", 331 */
323 msgId ); 332 Out_remove( fetch.serv, msgId );
324 else 333 if ( errStr[0] != '\0' )
325 returnArticleToSender( sender, errStr, txt ); 334 {
326 } 335 Utl_cpyStr( sender, Cfg_mailTo() );
336 if ( strcmp( sender, "" ) == 0
337 && ! Prt_searchHeader( txt, "SENDER", sender )
338 && ! Prt_searchHeader( txt, "X-NOFFLE-X-SENDER",
339 sender ) /* see server.c */
340 && ! Prt_searchHeader( txt, "FROM", sender ) )
341 Log_err( "Article %s has no From/Sender/X-Sender field",
342 msgId );
343 else
344 returnArticleToSender( sender, errStr, txt );
345 }
327 } 346 }
328 while ( Out_next( msgId, s ) ); 347 while ( Out_next( msgId, s ) );
329 } 348 }
330 del_DynStr( s ); 349 del_DynStr( s );
350 return res;
331 } 351 }
332 352
333 Bool 353 Bool
334 Fetch_init( const char *serv ) 354 Fetch_init( const char *serv )
335 { 355 {