comparison src/client.c @ 127:3c71e28c8eef noffle

[svn] Release-1-0 mergedocs/NOTES
author bears
date Tue, 25 Jul 2000 13:14:54 +0100
parents ec190bad201b
children d6c006a27ffe
comparison
equal deleted inserted replaced
126:7c7a7c96d35b 127:3c71e28c8eef
1 /* 1 /*
2 client.c 2 client.c
3 3
4 $Id: client.c 177 2000-07-22 06:21:11Z enz $ 4 $Id: client.c 183 2000-07-25 12:14:54Z 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
23 #include "content.h" 23 #include "content.h"
24 #include "control.h" 24 #include "control.h"
25 #include "dynamicstring.h" 25 #include "dynamicstring.h"
26 #include "group.h" 26 #include "group.h"
27 #include "itemlist.h" 27 #include "itemlist.h"
28 #include "lock.h"
28 #include "log.h" 29 #include "log.h"
29 #include "over.h" 30 #include "over.h"
30 #include "protocol.h" 31 #include "protocol.h"
31 #include "pseudo.h" 32 #include "pseudo.h"
32 #include "request.h" 33 #include "request.h"
267 alarm( 0 ); 268 alarm( 0 );
268 installSignalHandler( SIGALRM, oldHandler ); 269 installSignalHandler( SIGALRM, oldHandler );
269 return ( r >= 0 ); 270 return ( r >= 0 );
270 } 271 }
271 272
273 static DynStr *
274 collectTxt( void )
275 {
276 DynStr *res;
277 Str line;
278 Bool err;
279
280 res = new_DynStr(2048);
281 if ( res == NULL )
282 return NULL;
283
284 while ( getTxtLn( line, &err ) && ! err )
285 DynStr_appLn( res, line );
286
287 if ( err )
288 {
289 del_DynStr( res );
290 return NULL;
291 }
292 else
293 return res;
294 }
295
272 Bool 296 Bool
273 Client_connect( const char *serv ) 297 Client_connect( const char *serv )
274 { 298 {
275 unsigned short int port; 299 unsigned short int port;
276 int sock, i; 300 int sock, i;
278 struct hostent *hp; 302 struct hostent *hp;
279 char *pStart, *pColon; 303 char *pStart, *pColon;
280 Str host, s; 304 Str host, s;
281 struct sockaddr_in sIn; 305 struct sockaddr_in sIn;
282 306
307 ASSERT( client.in == NULL && client.out == NULL );
283 client.auth = FALSE; 308 client.auth = FALSE;
284 Utl_cpyStr( s, serv ); 309 Utl_cpyStr( s, serv );
285 pStart = Utl_stripWhiteSpace( s ); 310 pStart = Utl_stripWhiteSpace( s );
286 pColon = strstr( pStart, ":" ); 311 pColon = strstr( pStart, ":" );
287 if ( pColon == NULL ) 312 if ( pColon == NULL )
326 || ! ( client.in = fdopen( dup( sock ), "r" ) ) ) 351 || ! ( client.in = fdopen( dup( sock ), "r" ) ) )
327 { 352 {
328 if ( client.out != NULL ) 353 if ( client.out != NULL )
329 fclose( client.out ); 354 fclose( client.out );
330 close( sock ); 355 close( sock );
356 client.in = client.out = NULL;
331 break; 357 break;
332 } 358 }
333 stat = getStat(); 359 stat = getStat();
334 if ( stat == STAT_READY_POST_ALLOW || 360 if ( stat == STAT_READY_POST_ALLOW ||
335 stat == STAT_READY_NO_POST_ALLOW ) 361 stat == STAT_READY_NO_POST_ALLOW )
350 } 376 }
351 shutdown( fileno( client.out ), 0 ); 377 shutdown( fileno( client.out ), 0 );
352 fclose( client.in ); 378 fclose( client.in );
353 fclose( client.out ); 379 fclose( client.out );
354 close( sock ); 380 close( sock );
381 client.in = client.out = NULL;
355 } 382 }
356 } 383 }
357 return FALSE; 384 return FALSE;
358 } 385 }
359 386
416 443
417 return FALSE; 444 return FALSE;
418 } 445 }
419 446
420 static void 447 static void
421 processGrps( Bool noServerPattern ) 448 processGrps( const char *lines, Bool noServerPattern )
422 { 449 {
423 char postAllow; 450 char postAllow;
424 Bool err;
425 int first, last; 451 int first, last;
426 Str grp, line, file; 452 Str grp, line, file;
427 453 Bool groupupdate;
428 while ( getTxtLn( line, &err ) && ! err ) 454
455 ASSERT( ! Lock_gotLock() );
456 if ( ! Lock_openDatabases() )
457 return;
458
459 groupupdate = FALSE;
460 while ( ( lines = Utl_getLn( line, lines) ) != NULL )
429 { 461 {
430 if ( sscanf( line, "%s %d %d %c", 462 if ( sscanf( line, "%s %d %d %c",
431 grp, &last, &first, &postAllow ) != 4 ) 463 grp, &last, &first, &postAllow ) != 4 )
432 { 464 {
433 Log_err( "Unknown reply to LIST or NEWGROUPS: %s", line ); 465 Log_err( "Unknown reply to LIST or NEWGROUPS: %s", line );
452 Grp_setFirstLast( grp, first, first - 1 ); 484 Grp_setFirstLast( grp, first, first - 1 );
453 else 485 else
454 Grp_setFirstLast( grp, 1, 0 ); 486 Grp_setFirstLast( grp, 1, 0 );
455 Grp_setServ( grp, client.serv ); 487 Grp_setServ( grp, client.serv );
456 Grp_setPostAllow( grp, postAllow ); 488 Grp_setPostAllow( grp, postAllow );
489 groupupdate = TRUE;
457 } 490 }
458 else 491 else
459 { 492 {
460 if ( Cfg_servIsPreferential( client.serv, Grp_server( grp ) ) ) 493 if ( Cfg_servIsPreferential( client.serv, Grp_server( grp ) ) )
461 { 494 {
462 Log_inf( "Changing server for '%s': '%s'->'%s'", 495 Log_inf( "Changing server for '%s': '%s'->'%s'",
463 grp, Grp_server( grp ), client.serv ); 496 grp, Grp_server( grp ), client.serv );
464 Grp_setServ( grp, client.serv ); 497 Grp_setServ( grp, client.serv );
465 Grp_setRmtNext( grp, first ); 498 Grp_setRmtNext( grp, first );
466 Grp_setPostAllow( grp, postAllow ); 499 Grp_setPostAllow( grp, postAllow );
500 groupupdate = TRUE;
467 } 501 }
468 else 502 else
469 Log_dbg( "Group %s is already fetched from %s", 503 Log_dbg( "Group %s is already fetched from %s",
470 grp, Grp_server( grp ) ); 504 grp, Grp_server( grp ) );
471 505 }
472 } 506 }
473 } 507
474 if ( ! err ) 508 snprintf( file, MAXCHAR, "%s/lastupdate.%s",
475 { 509 Cfg_spoolDir(), client.serv );
476 snprintf( file, MAXCHAR, "%s/groupinfo.lastupdate", Cfg_spoolDir() ); 510 Utl_stamp( file );
477 Utl_stamp( file ); 511 if ( groupupdate )
478 } 512 {
513 snprintf( file, MAXCHAR, "%s/groupinfo.lastupdate",
514 Cfg_spoolDir() );
515 Utl_stamp( file );
516 }
517 Lock_closeDatabases();
479 } 518 }
480 519
481 void 520 void
482 Client_disconnect( void ) 521 Client_disconnect( void )
483 { 522 {
491 static Bool 530 static Bool
492 doGetGrps( const char *pattern, Bool *noServerPattern ) 531 doGetGrps( const char *pattern, Bool *noServerPattern )
493 { 532 {
494 Str cmd; 533 Str cmd;
495 int stat; 534 int stat;
535 DynStr *response;
496 536
497 Utl_cpyStr( cmd, "LIST ACTIVE" ); 537 Utl_cpyStr( cmd, "LIST ACTIVE" );
498 if ( pattern[ 0 ] != '\0' ) 538 if ( pattern[ 0 ] != '\0' )
499 { 539 {
500 Utl_catStr( cmd, " " ); 540 Utl_catStr( cmd, " " );
515 if ( stat != STAT_GRPS_FOLLOW ) 555 if ( stat != STAT_GRPS_FOLLOW )
516 { 556 {
517 Log_err( "%s failed: %s", cmd, client.lastStat ); 557 Log_err( "%s failed: %s", cmd, client.lastStat );
518 return FALSE; 558 return FALSE;
519 } 559 }
520 processGrps( *noServerPattern ); 560
561 response = collectTxt();
562 if ( response == NULL )
563 return FALSE;
564
565 processGrps( DynStr_str( response ), *noServerPattern );
566 del_DynStr( response );
521 return TRUE; 567 return TRUE;
522 } 568 }
523 569
524 Bool 570 Bool
525 Client_getGrps( void ) 571 Client_getGrps( void )
549 } 595 }
550 596
551 static Bool 597 static Bool
552 doGetDsc( const char *pattern, Bool *noServerPattern ) 598 doGetDsc( const char *pattern, Bool *noServerPattern )
553 { 599 {
554 Bool err;
555 Str name, line, dsc, cmd; 600 Str name, line, dsc, cmd;
556 int stat; 601 int stat;
557 602 DynStr *response;
603 const char *lines;
604
605 ASSERT( ! Lock_gotLock() );
558 Utl_cpyStr( cmd, "LIST NEWSGROUPS" ); 606 Utl_cpyStr( cmd, "LIST NEWSGROUPS" );
559 if ( pattern[ 0 ] != '\0' ) 607 if ( pattern[ 0 ] != '\0' )
560 { 608 {
561 Utl_catStr( cmd, " " ); 609 Utl_catStr( cmd, " " );
562 Utl_catStr( cmd, pattern ); 610 Utl_catStr( cmd, pattern );
576 if ( stat != STAT_GRPS_FOLLOW ) 624 if ( stat != STAT_GRPS_FOLLOW )
577 { 625 {
578 Log_err( "%s failed: %s", cmd, client.lastStat ); 626 Log_err( "%s failed: %s", cmd, client.lastStat );
579 return FALSE; 627 return FALSE;
580 } 628 }
581 while ( getTxtLn( line, &err ) && ! err ) 629
630 response = collectTxt();
631 if ( response == NULL )
632 return FALSE;
633
634 if ( ! Lock_openDatabases() )
635 return FALSE;
636
637 lines = DynStr_str( response );
638 while ( ( lines = Utl_getLn( line, lines) ) != NULL )
582 { 639 {
583 if ( sscanf( line, "%s", name ) != 1 ) 640 if ( sscanf( line, "%s", name ) != 1 )
584 { 641 {
585 Log_err( "Unknown reply to LIST NEWSGROUPS: %s", line ); 642 Log_err( "Unknown reply to LIST NEWSGROUPS: %s", line );
586 continue; 643 continue;
592 { 649 {
593 Log_dbg( "Description of %s: %s", name, dsc ); 650 Log_dbg( "Description of %s: %s", name, dsc );
594 Grp_setDsc( name, dsc ); 651 Grp_setDsc( name, dsc );
595 } 652 }
596 } 653 }
654 Lock_closeDatabases();
655 del_DynStr( response );
597 return TRUE; 656 return TRUE;
598 } 657 }
599 658
600 Bool 659 Bool
601 Client_getDsc( void ) 660 Client_getDsc( void )
622 681
623 del_GrEn( ge ); 682 del_GrEn( ge );
624 return res; 683 return res;
625 } 684 }
626 685
627 static Bool
628 doGetCreationTimes( const char *pattern, Bool *noServerPattern )
629 {
630 Bool err;
631 Str name, line, cmd;
632 time_t t;
633 int stat;
634
635 Utl_cpyStr( cmd, "LIST ACTIVE.TIMES" );
636 if ( pattern[ 0 ] != '\0' )
637 {
638 Utl_catStr( cmd, " " );
639 Utl_catStr( cmd, pattern );
640 }
641
642 *noServerPattern = FALSE;
643 if ( ! putCmd( cmd ) )
644 return FALSE;
645 stat = getStat();
646 if ( pattern[ 0 ] != '\0' && stat != STAT_GRPS_FOLLOW )
647 {
648 *noServerPattern= TRUE;
649 if ( ! putCmd( "LIST ACTIVE.TIMES" ) )
650 return FALSE;
651 stat = getStat();
652 }
653 if ( stat != STAT_GRPS_FOLLOW )
654 {
655 Log_err( "%s failed: %s", cmd, client.lastStat );
656 return FALSE;
657 }
658 while ( getTxtLn( line, &err ) && ! err )
659 {
660 if ( sscanf( line, "%s %ld", name, &t ) != 2 )
661 {
662 Log_err( "Unknown reply to LIST ACTIVE.TIMES: %s", line );
663 continue;
664 }
665 if ( *noServerPattern && ! isGetGroup( name ) )
666 continue;
667 if ( Grp_exists( name ) )
668 {
669 Log_inf( "Creation time of %s: %ld", name, t );
670 Grp_setCreated( name, t );
671 }
672 }
673 return TRUE;
674 }
675
676 Bool
677 Client_getCreationTimes( void )
678 {
679 GroupEnum *ge;
680 const char *pattern;
681 Bool doneOne, noServerPattern, res;
682
683 Log_inf( "Querying group creation times" );
684
685 doneOne = FALSE;
686 res = TRUE;
687 ge = new_GetGrEn( client.serv );
688 while ( res && ( pattern = GrEn_next( ge ) ) != NULL )
689 {
690 res = doGetCreationTimes( pattern, &noServerPattern );
691 doneOne = TRUE;
692 if ( noServerPattern )
693 break;
694 }
695
696 if ( ! doneOne )
697 res = doGetCreationTimes( "", &noServerPattern );
698
699 del_GrEn( ge );
700 return res;
701 }
702
703 Bool 686 Bool
704 Client_getNewgrps( const time_t *lastTime ) 687 Client_getNewgrps( const time_t *lastTime )
705 { 688 {
706 Str s; 689 Str s;
707 const char *p; 690 const char *p;
691 DynStr *response;
708 692
709 ASSERT( *lastTime > 0 ); 693 ASSERT( *lastTime > 0 );
710 strftime( s, MAXCHAR, "%Y%m%d %H%M00", gmtime( lastTime ) ); 694 strftime( s, MAXCHAR, "%Y%m%d %H%M00", gmtime( lastTime ) );
711 /* 695 /*
712 Do not use century for working with old server software until 2000. 696 Do not use century for working with old server software until 2000.
719 if ( getStat() != STAT_NEW_GRP_FOLLOW ) 703 if ( getStat() != STAT_NEW_GRP_FOLLOW )
720 { 704 {
721 Log_err( "NEWGROUPS command failed: %s", client.lastStat ); 705 Log_err( "NEWGROUPS command failed: %s", client.lastStat );
722 return FALSE; 706 return FALSE;
723 } 707 }
724 processGrps( TRUE ); 708
709 response = collectTxt();
710 if ( response == NULL )
711 return FALSE;
712
713 processGrps( DynStr_str( response ), TRUE );
714 del_DynStr( response );
725 return TRUE; 715 return TRUE;
726 } 716 }
727 717
728 static const char * 718 static const char *
729 readField( Str result, const char *p ) 719 readField( Str result, const char *p )
814 int status; 804 int status;
815 time_t lastAccess, nowTime; 805 time_t lastAccess, nowTime;
816 double threadFollowTime, secPerDay, maxTime, timeSinceLastAccess; 806 double threadFollowTime, secPerDay, maxTime, timeSinceLastAccess;
817 ItemList *itl; 807 ItemList *itl;
818 808
809 ASSERT( Lock_gotLock() );
819 Log_dbg( "Checking references '%s' for thread mode", ref ); 810 Log_dbg( "Checking references '%s' for thread mode", ref );
820 result = FALSE; 811 result = FALSE;
821 itl = new_Itl( ref, " \t" ); 812 itl = new_Itl( ref, " \t" );
822 nowTime = time( NULL ); 813 nowTime = time( NULL );
823 threadFollowTime = (double)Cfg_threadFollowTime(); 814 threadFollowTime = (double)Cfg_threadFollowTime();
860 { 851 {
861 Str g, t; 852 Str g, t;
862 const char *msgId, *p, *xref; 853 const char *msgId, *p, *xref;
863 int n; 854 int n;
864 855
856 ASSERT( Lock_gotLock() );
865 msgId = Ov_msgId( ov ); 857 msgId = Ov_msgId( ov );
866 if ( Pseudo_isGeneralInfo( msgId ) ) 858 if ( Pseudo_isGeneralInfo( msgId ) )
867 Log_dbg( "Skipping general info '%s'", msgId ); 859 Log_dbg( "Skipping general info '%s'", msgId );
868 else if ( Db_contains( msgId ) ) 860 else if ( Db_contains( msgId ) )
869 { 861 {
898 Db_prepareEntry( ov, client.grp, Ov_numb( ov ) ); 890 Db_prepareEntry( ov, client.grp, Ov_numb( ov ) );
899 } 891 }
900 } 892 }
901 893
902 Bool 894 Bool
903 Client_getOver( int rmtFirst, int rmtLast, FetchMode mode ) 895 Client_getOver( const char *grp, int rmtFirst, int rmtLast, FetchMode mode )
904 { 896 {
905 Bool err; 897 size_t nbytes, nlines;
906 size_t bytes, lines;
907 int rmtNumb, oldLast, cntMarked; 898 int rmtNumb, oldLast, cntMarked;
908 Over *ov; 899 Over *ov;
909 Str line, subj, from, date, msgId, ref; 900 Str line, subj, from, date, msgId, ref;
910 901 DynStr *response;
911 ASSERT( strcmp( client.grp, "" ) != 0 ); 902 const char *lines;
903
904 ASSERT( ! Lock_gotLock() );
905 ASSERT( strcmp( grp, "" ) != 0 );
912 if ( ! putCmd( "XOVER %lu-%lu", rmtFirst, rmtLast ) ) 906 if ( ! putCmd( "XOVER %lu-%lu", rmtFirst, rmtLast ) )
913 return FALSE; 907 return FALSE;
914 if ( getStat() != STAT_OVERS_FOLLOW ) 908 if ( getStat() != STAT_OVERS_FOLLOW )
915 { 909 {
916 Log_err( "XOVER command failed: %s", client.lastStat ); 910 Log_err( "XOVER command failed: %s", client.lastStat );
917 return FALSE; 911 return FALSE;
918 } 912 }
919 Log_dbg( "Requesting overview for remote %lu-%lu", rmtFirst, rmtLast ); 913 Log_dbg( "Requesting overview for remote %lu-%lu", rmtFirst, rmtLast );
914
915 response = collectTxt();
916 if ( response == NULL )
917 return FALSE;
918
919 if ( ! Lock_openDatabases() )
920 return FALSE;
921 Cont_read( grp );
920 oldLast = Cont_last(); 922 oldLast = Cont_last();
921 cntMarked = 0; 923 cntMarked = 0;
922 while ( getTxtLn( line, &err ) && ! err ) 924 lines = DynStr_str( response );
925 while ( ( lines = Utl_getLn( line, lines) ) != NULL )
923 { 926 {
924 if ( ! parseOvLn( line, &rmtNumb, subj, from, date, msgId, ref, 927 if ( ! parseOvLn( line, &rmtNumb, subj, from, date, msgId, ref,
925 &bytes, &lines ) ) 928 &nbytes, &nlines ) )
926 Log_err( "Bad overview line: %s", line ); 929 Log_err( "Bad overview line: %s", line );
927 else if ( Cont_find( msgId ) >= 0 ) 930 else if ( Cont_find( msgId ) >= 0 )
928 Log_inf( "Already have '%s'", msgId ); 931 Log_inf( "Already have '%s'", msgId );
929 else 932 else
930 { 933 {
931 ov = new_Over( subj, from, date, msgId, ref, bytes, lines ); 934 ov = new_Over( subj, from, date, msgId, ref, nbytes, nlines );
932 Cont_app( ov ); 935 Cont_app( ov );
933 prepareEntry( ov ); 936 prepareEntry( ov );
934 if ( mode == FULL || ( mode == THREAD && needsMark( ref ) ) ) 937 if ( mode == FULL || ( mode == THREAD && needsMark( ref ) ) )
935 { 938 {
936 Req_add( client.serv, msgId ); 939 Req_add( client.serv, msgId );
940 Grp_setRmtNext( client.grp, rmtNumb + 1 ); 943 Grp_setRmtNext( client.grp, rmtNumb + 1 );
941 } 944 }
942 if ( oldLast != Cont_last() ) 945 if ( oldLast != Cont_last() )
943 Log_inf( "Added %s %lu-%lu", client.grp, oldLast + 1, Cont_last() ); 946 Log_inf( "Added %s %lu-%lu", client.grp, oldLast + 1, Cont_last() );
944 Log_inf( "%u articles marked for download in %s", cntMarked, client.grp ); 947 Log_inf( "%u articles marked for download in %s", cntMarked, client.grp );
945 return err; 948 Cont_write();
949 Grp_setFirstLast( grp, Cont_first(), Cont_last() );
950 Lock_closeDatabases();
951 del_DynStr( response );
952 return TRUE;
946 } 953 }
947 954
948 static void 955 static void
949 retrievingFailed( const char* msgId, const char *reason ) 956 retrievingFailed( const char* msgId, const char *reason )
950 { 957 {
951 int status; 958 int status;
952 959
960 ASSERT( ! Lock_gotLock() );
953 Log_err( "Retrieving of %s failed: %s", msgId, reason ); 961 Log_err( "Retrieving of %s failed: %s", msgId, reason );
962 if ( ! Lock_openDatabases() )
963 return;
954 status = Db_status( msgId ); 964 status = Db_status( msgId );
955 Pseudo_retrievingFailed( msgId, reason ); 965 Pseudo_retrievingFailed( msgId, reason );
956 Db_setStatus( msgId, status | DB_RETRIEVING_FAILED ); 966 Db_setStatus( msgId, status | DB_RETRIEVING_FAILED );
967 Lock_closeDatabases();
957 } 968 }
958 969
959 static Bool 970 static Bool
960 retrieveAndStoreArt( const char *msgId, int artcnt, int artmax ) 971 retrieveAndStoreArt( const char *msgId, int artcnt, int artmax )
961 { 972 {
962 Bool err; 973 Bool err;
963 DynStr *s = NULL; 974 DynStr *s = NULL;
964 Str line; 975
965 976 ASSERT( ! Lock_gotLock() );
966 Log_inf( "[%d/%d] Retrieving %s", artcnt, artmax, msgId ); 977 Log_inf( "[%d/%d] Retrieving %s", artcnt, artmax, msgId );
967 s = new_DynStr( 5000 ); 978 err = TRUE;
968 while ( getTxtLn( line, &err ) && ! err ) 979
969 DynStr_appLn( s, line ); 980 s = collectTxt();
970 if ( ! err ) 981 if ( s != NULL )
971 { 982 {
972 const char *txt; 983 const char *txt;
973 984
974 txt = DynStr_str( s ); 985 txt = DynStr_str( s );
986 if ( ! Lock_openDatabases() )
987 {
988 del_DynStr( s );
989 retrievingFailed( msgId, "Can't open message base" );
990 return FALSE;
991 }
992
975 err = ! Db_storeArt( msgId, txt ); 993 err = ! Db_storeArt( msgId, txt );
976 if ( ! err ) 994 if ( ! err )
977 { 995 {
978 Str supersedeIds; 996 Str supersedeIds;
979 997
988 supersededMsgId = Itl_next( ids ) ) 1006 supersededMsgId = Itl_next( ids ) )
989 Ctrl_cancel( supersededMsgId ); 1007 Ctrl_cancel( supersededMsgId );
990 del_Itl( ids ); 1008 del_Itl( ids );
991 } 1009 }
992 } 1010 }
1011 Lock_closeDatabases();
1012 del_DynStr( s );
993 } 1013 }
994 else 1014 else
995 retrievingFailed( msgId, "Connection broke down" ); 1015 retrievingFailed( msgId, "Connection broke down" );
996 del_DynStr( s );
997 return ! err; 1016 return ! err;
998 } 1017 }
999 1018
1000 void 1019 void
1001 Client_retrieveArt( const char *msgId ) 1020 Client_retrieveArt( const char *msgId )
1002 { 1021 {
1022 ASSERT( Lock_gotLock() );
1003 if ( ! Db_contains( msgId ) ) 1023 if ( ! Db_contains( msgId ) )
1004 { 1024 {
1005 Log_err( "Article '%s' not prepared in database. Skipping.", msgId ); 1025 Log_err( "Article '%s' not prepared in database. Skipping.", msgId );
1006 return; 1026 return;
1007 } 1027 }
1008 if ( ! ( Db_status( msgId ) & DB_NOT_DOWNLOADED ) ) 1028 if ( ! ( Db_status( msgId ) & DB_NOT_DOWNLOADED ) )
1009 { 1029 {
1010 Log_inf( "Article '%s' already retrieved. Skipping.", msgId ); 1030 Log_inf( "Article '%s' already retrieved. Skipping.", msgId );
1011 return; 1031 return;
1012 } 1032 }
1033
1034 Lock_closeDatabases();
1013 if ( ! putCmd( "ARTICLE %s", msgId ) ) 1035 if ( ! putCmd( "ARTICLE %s", msgId ) )
1014 retrievingFailed( msgId, "Connection broke down" ); 1036 retrievingFailed( msgId, "Connection broke down" );
1015 else if ( getStat() != STAT_ART_FOLLOWS ) 1037 else if ( getStat() != STAT_ART_FOLLOWS )
1016 retrievingFailed( msgId, client.lastStat ); 1038 retrievingFailed( msgId, client.lastStat );
1017 else 1039 else
1023 { 1045 {
1024 Str msgId; 1046 Str msgId;
1025 DynStr *s; 1047 DynStr *s;
1026 const char *p; 1048 const char *p;
1027 1049
1050 ASSERT( Lock_gotLock() );
1028 Log_inf( "Retrieving article list" ); 1051 Log_inf( "Retrieving article list" );
1029 s = new_DynStr( (int)strlen( list ) ); 1052 s = new_DynStr( (int)strlen( list ) );
1030 p = list; 1053 p = list;
1031 while ( ( p = Utl_getLn( msgId, p ) ) ) 1054 while ( ( p = Utl_getLn( msgId, p ) ) )
1032 if ( ! Db_contains( msgId ) ) 1055 if ( ! Db_contains( msgId ) )
1040 del_DynStr( s ); 1063 del_DynStr( s );
1041 return; 1064 return;
1042 } 1065 }
1043 else 1066 else
1044 DynStr_appLn( s, msgId ); 1067 DynStr_appLn( s, msgId );
1068
1069 Lock_closeDatabases();
1045 fflush( client.out ); 1070 fflush( client.out );
1046 Log_dbg( "[S FLUSH]" ); 1071 Log_dbg( "[S FLUSH]" );
1072
1047 p = DynStr_str( s ); 1073 p = DynStr_str( s );
1048 while ( ( p = Utl_getLn( msgId, p ) ) ) 1074 while ( ( p = Utl_getLn( msgId, p ) ) )
1049 { 1075 {
1050 if ( getStat() != STAT_ART_FOLLOWS ) 1076 if ( getStat() != STAT_ART_FOLLOWS )
1051 retrievingFailed( msgId, client.lastStat ); 1077 retrievingFailed( msgId, client.lastStat );
1052 else if ( ! retrieveAndStoreArt( msgId, ++(*artcnt), artmax ) ) 1078 else if ( ! retrieveAndStoreArt( msgId, ++(*artcnt), artmax ) )
1053 break; 1079 break;
1054 } 1080 }
1055 del_DynStr( s ); 1081 del_DynStr( s );
1082 Lock_openDatabases();
1056 } 1083 }
1057 1084
1058 Bool 1085 Bool
1059 Client_changeToGrp( const char* name ) 1086 Client_changeToGrp( const char* name )
1060 { 1087 {
1061 unsigned int stat; 1088 unsigned int stat;
1062 int estimatedNumb, first, last; 1089 int estimatedNumb, first, last;
1063 1090
1091 ASSERT( Lock_gotLock() );
1064 if ( ! Grp_exists( name ) ) 1092 if ( ! Grp_exists( name ) )
1065 return FALSE; 1093 return FALSE;
1066 if ( ! putCmd( "GROUP %s", name ) ) 1094 if ( ! putCmd( "GROUP %s", name ) )
1067 return FALSE; 1095 return FALSE;
1068 if ( getStat() != STAT_GRP_SELECTED ) 1096 if ( getStat() != STAT_GRP_SELECTED )
1080 } 1108 }
1081 1109
1082 void 1110 void
1083 Client_rmtFirstLast( int *first, int *last ) 1111 Client_rmtFirstLast( int *first, int *last )
1084 { 1112 {
1113 ASSERT( Lock_gotLock() );
1085 *first = client.rmtFirst; 1114 *first = client.rmtFirst;
1086 *last = client.rmtLast; 1115 *last = client.rmtLast;
1087 } 1116 }
1088 1117
1089 Bool 1118 Bool