home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / vsoup128.zip / main.cc < prev    next >
C/C++ Source or Header  |  1997-04-20  |  19KB  |  689 lines

  1. //  $Id: main.cc 1.33 1997/04/20 19:11:34 hardy Exp $
  2. //
  3. //  This progam/module was written by Hardy Griech based on ideas and
  4. //  pieces of code from Chin Huang (cthuang@io.org).  Bug reports should
  5. //  be submitted to rgriech@swol.de.
  6. //
  7. //  This file is part of VSoup for OS/2.  VSoup including this file
  8. //  is freeware.  There is no warranty of any kind implied.  The terms
  9. //  of the GNU Gernal Public Licence are valid for this piece of software.
  10. //
  11. //  Fetch mail and news using POP3 and NNTP into a SOUP packet.
  12. //
  13.  
  14. #include <assert.h>
  15. #include <stdarg.h>
  16. #include <string.h>
  17. #include <signal.h>
  18. #include <getopt.h>
  19. #include <time.h>
  20. #include <unistd.h>
  21.  
  22. //
  23. //  für TCPOS2.INI-Leserei
  24. //
  25. #ifdef OS2
  26. #define INCL_WINSHELLDATA
  27. #include <os2.h>
  28. #endif
  29.  
  30. #define DEFGLOBALS
  31. #include "areas.hh"
  32. #include "global.hh"
  33. #include "mts.hh"
  34. #include "news.hh"
  35. #include "pop3.hh"
  36. #include "reply.hh"
  37. #include "socket.hh"
  38. #include "util.hh"
  39.  
  40.  
  41. #define VERSION "VSoup v1.2.8 (rg190497)"
  42.  
  43.  
  44. static enum { RECEIVE, SEND, CATCHUP } mode = RECEIVE;
  45. static char doMail = 1;
  46. static char doNews = 1;
  47. static char doSummary = 0;
  48. static int  catchupCount;
  49. static clock_t startTime;
  50. static long minThroughput = 0;
  51. static int  threadCntGiven = 0;
  52. static int  newsStrategy = 1;
  53. #ifdef OS2
  54. static char doIni = 1;        // if TRUE, read TCPOS2.INI file
  55. #endif
  56.  
  57.  
  58.  
  59. static void prepareAbort( void )
  60. {
  61.     doAbortProgram = 1;
  62.     TSocket::abortAll();
  63. }   // prepareAbort
  64.  
  65.  
  66.  
  67. static void setFiles( void )
  68. {
  69. #ifdef OS2
  70.     sprintfT(newsrcFile, "%s/newsrc", homeDir);
  71.     sprintfT(killFile, "%s/score", homeDir);
  72. #else
  73.     sprintfT(newsrcFile, "%s/.newsrc", homeDir);
  74.     sprintfT(killFile, "%s/.score", homeDir);
  75. #endif
  76. }   // setFiles
  77.  
  78.  
  79.  
  80. static void getUrlInfo( const char *url, serverInfo &info )
  81. //
  82. //  Get an URL in the form [user[:passwd]@]host[:port]
  83. //  This routine changes only existing fields in 'info'.
  84. //  restrictions:
  85. //  - not optimized for speed
  86. //  - single field length limited to 512 chars (not checked)
  87. //  - portno 0 not allowed
  88. //  - can be fooled easily (with illegal URL specs)
  89. //
  90. {
  91.     char user[512];
  92.     char host[512];
  93.     char username[512];
  94.     char passwd[512];
  95.     char hostname[512];
  96.     char port[512];
  97.  
  98.     if (sscanfT(url,"%[^@]@%s",user,host) == 2) {
  99.     if (sscanfT(user,"%[^:]:%s",username,passwd) == 2) {
  100.         xstrdup( &info.user,username );
  101.         xstrdup( &info.passwd,passwd );
  102.     }
  103.     else
  104.         xstrdup( &info.user,user );
  105.     }
  106.     else
  107.     strcpy( host,url );
  108.  
  109.     if (sscanfT(host,"%[^:]:%s",hostname,port) == 2) {
  110.     xstrdup( &info.host,hostname );
  111.     if (atoi(port) != 0)
  112.         info.port = atoi(port);
  113.     }
  114.     else
  115.     xstrdup( &info.host,host );
  116.  
  117. #ifdef TRACE
  118.     printfT( "getUrlInfo(%s): %s:%s@%s:%d\n",url,info.user,info.passwd,info.host,info.port );
  119. #endif
  120. }   // getUrlInfo
  121.  
  122.  
  123.  
  124. static void checkTransfer( void * )
  125. //
  126. //  check transfer...
  127. //
  128. {
  129.     long timeCnt;
  130.     long throughputCnt;
  131.     int  throughputErr;
  132.     long oldXfer, curXfer;
  133.  
  134. #ifdef WININITIALIZE
  135.     WinInitialize(0);
  136. #endif
  137.  
  138.     timeCnt = 0;
  139.     oldXfer  = 0;
  140.     throughputCnt = 0;
  141.     throughputErr = 6;
  142.     for (;;) {
  143.     sleep( 1 );
  144.     if (doAbortProgram)
  145.         break;
  146.     
  147.     ++timeCnt;
  148.     curXfer = TSocket::getBytesRcvd() + TSocket::getBytesXmtd();
  149.  
  150.     //
  151.     //  check connect timeout
  152.     //
  153.     if (curXfer < 100  &&  timeCnt > 100) {
  154.         areas.mailPrintf1( 1,"\n\ncannot connect -> signal %d generated\n",
  155.                    SIGINT );
  156. #ifdef TRACE_ALL
  157.         printfT( "checkTransfer():  TIMEOUT\n" );
  158. #endif
  159. #ifdef NDEBUG
  160.         kill( getpid(),SIGINT );
  161. #else
  162.         areas.mailPrintf1( 1,"NDEBUG not defined -> no signal generated\n" );
  163. #endif
  164.         break;
  165.     }
  166.  
  167.     //
  168.     //  check throughput
  169.     //  6 times lower than minThroughput -> generate signal
  170.     //  - minThroughput is mean transferrate over 10s
  171.     //  - minThroughput == -1  ->  disable throughput checker
  172.     //
  173.     ++throughputCnt;
  174.     if (curXfer == 0)
  175.         throughputCnt = 0;
  176.     if (throughputCnt >= 10) {
  177.         long xfer = curXfer-oldXfer;
  178.  
  179.         if (xfer/throughputCnt > labs(minThroughput)  ||  minThroughput == -1)
  180.         throughputErr = 6;
  181.         else {
  182.         --throughputErr;
  183.         if (throughputErr < 0) {
  184.             areas.mailPrintf1( 1,"\n\nthroughput lower/equal than %ld bytes/s -> signal %d generated\n",
  185.                        labs(minThroughput),SIGINT );
  186. #ifdef TRACE_ALL
  187.             printfT( "checkTransfer():  THROUGHPUT\n" );
  188. #endif
  189. #ifdef NDEBUG
  190.             kill( getpid(),SIGINT );
  191. #else
  192.             throughputCnt = 30;
  193. #endif
  194.             break;
  195.         }
  196.         }
  197.         if (minThroughput < -1)
  198.         areas.mailPrintf1( 1,"throughput: %lu bytes/s, %d fail sample%s left\n",
  199.                    xfer/throughputCnt,throughputErr,
  200.                    (throughputErr == 1) ? "" : "s");
  201.         oldXfer = curXfer;
  202.         throughputCnt = 0;
  203.     }
  204.     }
  205. }   // checkTransfer
  206.  
  207.  
  208.  
  209. static void openAreasAndStartTimer( int argc, char **argv )
  210. {
  211.     int i;
  212.     char serverNames[BUFSIZ];
  213.  
  214.     //
  215.     //  put for operation important server names into status mail header
  216.     //
  217.     strcpy( serverNames,"" );
  218.     if (nntpInfo.host != NULL  &&
  219.     (mode == CATCHUP  ||  mode == SEND  ||  (mode == RECEIVE  &&  doNews))) {
  220.     strcat( serverNames,nntpInfo.host );
  221.     strcat( serverNames," " );
  222.     }
  223.     if (pop3Info.host != NULL  &&  mode == RECEIVE  &&  doMail) {
  224.     strcat( serverNames,pop3Info.host );
  225.     strcat( serverNames," " );
  226.     }
  227.     if (smtpInfo.host != NULL  &&  mode == SEND)
  228.     strcat( serverNames,smtpInfo.host );
  229.     areas.mailOpen( serverNames );
  230.  
  231.     //
  232.     //  write all given paramters into StsMail (no passwords...)
  233.     //
  234.     areas.mailStart();
  235.     areas.mailPrintf( "%s started\n", VERSION );
  236.     for (i = 0;  i < argc;  ++i)
  237.     areas.mailPrintf( "%s%s", (i == 0) ? "" : " ", argv[i] );
  238.     areas.mailPrintf( "\n" );
  239.     areas.mailPrintf( "home directory: %s\n", homeDir );
  240.     areas.mailPrintf( "newsrc file:    %s\n", newsrcFile );
  241.     areas.mailPrintf( "kill file:      %s\n", killFile );
  242.     if (mode == CATCHUP  ||  mode == SEND  ||  (mode == RECEIVE  &&  doNews)) {
  243.     areas.mailPrintf( "nntp server:    nntp://%s%s%s",
  244.               (nntpInfo.user != NULL) ? nntpInfo.user : "",
  245.               (nntpInfo.user != NULL) ? ":*@" : "", nntpInfo.host );
  246.     if (nntpInfo.port != -1)
  247.         areas.mailPrintf( ":%d", nntpInfo.port );
  248.     areas.mailPrintf( "\n" );
  249.     }
  250.     if (mode == RECEIVE  &&  doMail) {
  251.     areas.mailPrintf( "pop3 server:    pop3://%s%s%s",
  252.               (pop3Info.user != NULL) ? pop3Info.user : "",
  253.               (pop3Info.user != NULL) ? ":*@" : "", pop3Info.host );
  254.     if (pop3Info.port != -1)
  255.         areas.mailPrintf( ":%d", pop3Info.port );
  256.     areas.mailPrintf( "\n" );
  257.     }
  258.     if (mode == SEND) {
  259.     areas.mailPrintf( "smtp gateway:   smtp://%s", smtpInfo.host );
  260.     if (smtpInfo.port != -1)
  261.         areas.mailPrintf( ":%d", smtpInfo.port );
  262.     areas.mailPrintf( "\n" );
  263.     }
  264.     areas.mailStop();
  265.  
  266.     startTime = clock();
  267. }   // openAreasAndStartTimer
  268.  
  269.  
  270.  
  271. static void stopTimerEtc( int retcode )
  272. {
  273.     clock_t deltaTime;
  274.     long deltaTimeS10;
  275.  
  276.     if (TSocket::getBytesRcvd() + TSocket::getBytesXmtd() != 0) {
  277.     deltaTime = clock() - startTime;
  278.     deltaTimeS10 = (10*deltaTime) / CLOCKS_PER_SEC;
  279.     if (deltaTimeS10 == 0)
  280.         deltaTimeS10 = 1;
  281.     areas.mailPrintf1( 1,"%s: totally %lu bytes received, %lu bytes transmitted\n",
  282.                progname, TSocket::getBytesRcvd(), TSocket::getBytesXmtd() );
  283.     areas.mailPrintf1( 1,"%s: %ld.%ds elapsed, throughput %ld bytes/s\n",progname,
  284.                deltaTimeS10 / 10, deltaTimeS10 % 10,
  285.                (10*(TSocket::getBytesRcvd()+TSocket::getBytesXmtd())) / deltaTimeS10 );
  286.     }
  287.  
  288.     areas.mailStart();
  289.     areas.mailPrintf( "%s finished, retcode=%d\n", progname,retcode );
  290.     areas.mailStop();
  291. }   // stopTimerEtc
  292.  
  293.  
  294.  
  295. static void usage( const char *fmt, ... )
  296. {
  297.     va_list ap;
  298.  
  299.     if (fmt != NULL) {
  300.     char buf[BUFSIZ];
  301.     
  302.     va_start( ap,fmt );
  303.     vsprintfT( buf,fmt,ap );
  304.     va_end( ap );
  305.     areas.mailPrintf1( 1,"%s\n",buf );
  306.     }
  307.  
  308.     hprintfT( STDERR_FILENO, "%s - transfer POP3 mail and NNTP news to SOUP\n",VERSION );
  309.     hprintfT( STDERR_FILENO, "usage: %s [options] [URLs]\n",progname );
  310.     hputsT("  URL:  (nntp|pop3|smtp)://[userid[:password]@]host[:port]\n",STDERR_FILENO );
  311.     hputsT("global options:\n",STDERR_FILENO );
  312.     hputsT("  -h dir   Set home directory\n", STDERR_FILENO);
  313. #ifdef OS2
  314.     hputsT("  -i       Do not read 'Internet Connection for OS/2' settings\n", STDERR_FILENO);
  315. #endif
  316.     hputsT("  -m       Do not get mail\n", STDERR_FILENO);
  317.     hputsT("  -M       generate status mail\n", STDERR_FILENO);
  318.     hputsT("  -n       Do not get news\n", STDERR_FILENO);
  319.     hputsT("  -r       Read only mode.  Do not delete mail or update newsrc\n", STDERR_FILENO);
  320.     hputsT("  -s       Send replies\n", STDERR_FILENO);
  321.     hputsT("  -T n     limit for throughput surveillance [default: 0]\n", STDERR_FILENO);
  322.  
  323.     hputsT("news reading options:\n", STDERR_FILENO);
  324.     hputsT("  -a       Add new newsgroups to newsrc file\n", STDERR_FILENO);
  325.     hputsT("  -c[n]    Mark every article as read except for the last n [default: 10]\n", STDERR_FILENO);
  326.     hputsT("  -k n     Set maximum news packet size in kBytes\n", STDERR_FILENO);
  327.     hputsT("  -K file  Set score file\n", STDERR_FILENO);
  328.     hputsT("  -N file  Set newsrc file\n", STDERR_FILENO);
  329. #if defined(OS2)  &&  defined(__MT__)
  330.     hputsT("  -S n     News reading strategy [0..2, default 1]\n", STDERR_FILENO );
  331.     hprintfT( STDERR_FILENO,"  -t n     Number of threads [1..%d, standard: %d]\n",
  332.           MAXNNTPTHREADS,DEFNNTPTHREADS );
  333. #endif
  334.     hputsT("  -u       Create news summary\n", STDERR_FILENO);
  335.     hputsT("  -x       Do not process news Xref headers\n", STDERR_FILENO);
  336.     hputsT( "mail reading option:\n", STDERR_FILENO );
  337.     hputsT("  -D       force deletion of mail on POP3 server on each message\n", STDERR_FILENO );
  338.  
  339.     assert( _heapchk() == _HEAPOK );
  340.  
  341.     areas.forceMail();
  342.     areas.closeAll();
  343.  
  344.     assert( _heapchk() == _HEAPOK );
  345.  
  346.     exit( EXIT_FAILURE );
  347. }   // usage
  348.  
  349.  
  350.  
  351. static void parseCmdLine( int argc, char **argv, int doAction )
  352. {
  353.     int c;
  354.     int i;
  355.  
  356.     optind = 0;
  357.     while ((c = getopt(argc, argv, "?ac::Dh:iK:k:MmN:nrsS:t:T:ux")) != EOF) {
  358.     if (!doAction) {
  359. #ifdef OS2
  360.         if (c == 'i')
  361.         doIni = 0;
  362. #endif
  363.     }
  364.     else {
  365.         switch (c) {
  366.         case '?':
  367.             usage( NULL );
  368.             break;
  369.         case 'a':
  370.             doNewGroups = 1;
  371.             break;
  372.         case 'c':
  373.             mode = CATCHUP;
  374.             if (optarg != NULL) {
  375.             catchupCount = atoi(optarg);
  376.             if (catchupCount < 0)
  377.                 catchupCount = 0;
  378.             }
  379.             else
  380.             catchupCount = 10;
  381.             break;
  382.         case 'D':
  383.             forceMailDelete = 1;
  384.             break;
  385.         case 'h':
  386.             homeDir = optarg;
  387.             setFiles();
  388.             break;
  389. #ifdef OS2
  390.         case 'i':
  391.             break;
  392. #endif
  393.         case 'K':
  394.             strcpy(killFile, optarg);
  395.             killFileOption = 1;
  396.             break;
  397.         case 'k':
  398.             maxBytes = atol(optarg) * 1000L;
  399.             break;
  400.         case 'M':
  401.             areas.forceMail();
  402.             break;
  403.         case 'm':
  404.             doMail = 0;
  405.             break;
  406.         case 'N':
  407.             strcpy(newsrcFile, optarg);
  408.             break;
  409.         case 'n':
  410.             doNews = 0;
  411.             break;
  412.         case 'r':
  413.             readOnly = 1;
  414.             break;
  415.         case 's':
  416.             mode = SEND;
  417.             break;
  418. #if defined(OS2)  &&  defined(__MT__)
  419.         case 'S':
  420.             newsStrategy = atoi(optarg);
  421.             break;
  422.         case 't':
  423.             maxNntpThreads = atoi(optarg);
  424.             if (maxNntpThreads < 1  ||  maxNntpThreads > MAXNNTPTHREADS)
  425.             usage( "ill num of threads %s",optarg );
  426.             threadCntGiven = 1;
  427.             break;
  428. #endif
  429.         case 'T':
  430.             minThroughput = atol(optarg);
  431.             break;
  432.         case 'u':
  433.             doNews = 1;
  434.             doSummary = 1;
  435.             break;
  436.         case 'x':
  437.             doXref = 0;
  438.             break;
  439.         default:
  440.             usage( NULL );
  441.         }
  442.     }
  443.     }
  444.  
  445.     //
  446.     //  get the URLs
  447.     //
  448.     if (doAction) {
  449.     for (i = optind;  i < argc;  i++) {
  450.         if (strnicmp("smtp://",argv[i],7) == 0)
  451.         getUrlInfo( argv[i]+7, smtpInfo );
  452.         else if (strnicmp("pop3://",argv[i],7) == 0)
  453.         getUrlInfo( argv[i]+7, pop3Info );
  454.         else if (strnicmp("nntp://",argv[i],7) == 0)
  455.         getUrlInfo( argv[i]+7, nntpInfo );
  456.         else
  457.         usage( "ill URL %s",argv[i] );
  458.     }
  459.     }
  460. }   // parseCmdLine
  461.  
  462.  
  463.  
  464. #ifdef OS2
  465. static void readTcpIni (void)
  466. {
  467.     HAB hab;
  468.     HINI hini;
  469.     char *etc;
  470.     char buf[BUFSIZ];
  471.     char curConnect[200];
  472.  
  473.     etc = getenv("ETC");
  474.     if (etc == NULL) {
  475.     hputsT( "Must set ETC\n", STDERR_FILENO );
  476.     exit( EXIT_FAILURE );
  477.     }
  478.     sprintfT(buf, "%s\\TCPOS2.INI", etc);
  479.  
  480.     hab = WinInitialize(0);
  481.     hini = PrfOpenProfile(hab, buf);
  482.     if (hini == NULLHANDLE) {
  483.     hprintfT( STDERR_FILENO, "cannot open profile %s\n", buf );
  484.     exit(EXIT_FAILURE);
  485.     }
  486.  
  487.     PrfQueryProfileString(hini, "CONNECTION", "CURRENT_CONNECTION", "",
  488.                           curConnect, sizeof(curConnect));
  489.  
  490.     PrfQueryProfileString(hini, curConnect, "POPSRVR", "", buf, sizeof(buf));
  491.     xstrdup( &pop3Info.host,buf );
  492.     PrfQueryProfileString(hini, curConnect, "POP_ID", "", buf, sizeof(buf));
  493.     xstrdup( &pop3Info.user,buf );
  494.     xstrdup( &smtpInfo.user,buf );
  495.     xstrdup( &nntpInfo.user,buf );
  496.     PrfQueryProfileString(hini, curConnect, "POP_PWD", "", buf, sizeof(buf));
  497.     xstrdup( &pop3Info.passwd,buf );
  498.     xstrdup( &smtpInfo.passwd,buf );
  499.     xstrdup( &nntpInfo.passwd,buf );    
  500.  
  501.     PrfQueryProfileString(hini, curConnect, "DEFAULT_NEWS", "", buf, sizeof(buf));
  502.     xstrdup( &nntpInfo.host,buf );
  503.  
  504.     PrfQueryProfileString(hini, curConnect, "MAIL_GW", "", buf, sizeof(buf));
  505.     xstrdup( &smtpInfo.host,buf );
  506.     
  507.     PrfCloseProfile(hini);
  508.     WinTerminate(hab);
  509.  
  510. #ifdef DEBUG
  511.     printfT( "TCPOS2.INI information:\n" );
  512.     printfT( "-----------------------\n" );
  513.     printfT( "nntpServer:   %s\n", nntpInfo.host );
  514.     printfT( "popServer:    %s\n", pop3Info.host );
  515.     printfT( "mailGateway:  %s\n", smtpInfo.host );
  516.     printfT( "-----------------------\n" );
  517. #endif
  518. }   // readTcpIni
  519. #endif
  520.  
  521.  
  522.  
  523. static void signalHandler( int signo )
  524. //
  525. //  Signal handling:
  526. //  -  abort the sockets (sockets are unblocked...)
  527. //  -  close the files
  528. //  -  output an error message
  529. //
  530. //  es ist sehr die Frage, ob man hier sprintfT etc verwenden darf, da nicht 100%
  531. //  klar ist, ob ein abgeschossener Thread die zugehörigen Semaphore freigibt!? (scheint aber so...)
  532. //
  533. {
  534.     //
  535.     //  if SIGINT will be received, consecutive reception of the signal
  536.     //  will be disabled.  Otherwise set handling to default
  537.     //  (e.g. SIGTERM twice will terminate also signalHandler())
  538.     //
  539.     signal( signo, (signo == SIGUSR1  ||  signo == SIGINT) ? SIG_IGN : SIG_DFL );
  540.     signal( signo, SIG_ACK );
  541.  
  542. #ifndef NDEBUG
  543.     printfT( "\nmain thread received signal %d\n",signo );
  544. #endif
  545.  
  546.     prepareAbort();
  547.  
  548.     //  durch's Abbrechen gibt es manchmal einen SIGSEGV der sub-threads, da sie
  549.     //  z.B. auf eine Datei zugreifen, die schon geschlossen wurde.
  550.     //  die Kinder müssen zuerst gekillt werden (aber wie??)
  551.     //  Holzhammer:  die Threads brechen bei SIGSEGV ab.  Die Sockets werden auf
  552.     //  NONBLOCK gestellt und lösen ein SIGUSR1 aus, wenn abgebrochen werden soll
  553.     //
  554.  
  555.     areas.mailException();          // otherwise semaphors could block forever
  556.     
  557.     areas.mailPrintf1( 1,"\n*** signal %d received ***\n\n",signo );
  558.  
  559.     stopTimerEtc( EXIT_FAILURE );
  560.  
  561.     areas.forceMail();          // generate status mail in case of signal reception
  562.     areas.closeAll();
  563.  
  564.     if ( !readOnly)
  565.     newsrc.writeFile();
  566.  
  567.     exit( EXIT_FAILURE );       // wird ein raise() gemacht, so werden die exit-Routinen nicht aufgerufen (z.B. files löschen)
  568. }   // signalHandler
  569.  
  570.  
  571.  
  572. int main( int argc, char **argv )
  573. {
  574.     int retcode = EXIT_SUCCESS;
  575.     char *s;
  576.     
  577. #ifdef DEBUG
  578.     setvbuf( stdout,NULL,_IONBF,0 );
  579. #endif
  580.  
  581. #ifdef OS2
  582.     if (_osmode != OS2_MODE) {
  583.     hprintfT( STDERR_FILENO,"sorry, DOS not sufficient...\n" );
  584.     exit( EXIT_FAILURE );
  585.     }
  586. #endif
  587.     
  588.     signal(SIGINT,   signalHandler );     // ^C
  589.     signal(SIGBREAK, signalHandler );     // ^Break
  590.     signal(SIGHUP,   signalHandler );     // hang up
  591.     signal(SIGPIPE,  signalHandler );     // broken pipe
  592.     signal(SIGTERM,  signalHandler );     // kill (läßt der sich doch catchen?)
  593.     signal(SIGUSR1,  SIG_IGN );           // ignore this signal in the main thread (which should not be aborted...)
  594.     
  595.     progname = strrchr(argv[0], '\\');
  596.     if (progname == NULL)
  597.     progname = argv[0];
  598.     else
  599.     ++progname;
  600.  
  601.     //
  602.     //  get some environment vars (HOME, NNTPSERVER)
  603.     //
  604.     parseCmdLine(argc, argv, 0);    // only get doIni (-i)
  605. #ifdef OS2
  606.     if (doIni)
  607.     readTcpIni();
  608. #endif
  609.     if ((homeDir = getenv("HOME")) == NULL)
  610.     homeDir = ".";
  611.     if ((s = getenv("NNTPSERVER")) != NULL)
  612.     getUrlInfo( getenv("NNTPSERVER"), nntpInfo );
  613.     setFiles();
  614.     parseCmdLine(argc, argv, 1);
  615.     
  616.     assert( _heapchk() == _HEAPOK );
  617.  
  618.     //
  619.     //  check the number of free file handles
  620.     //
  621. #ifndef HANDLEERR
  622.     if (mode == RECEIVE  &&  doNews) {
  623.     int h = nhandles(150);    // maximum 150 handles
  624.  
  625. #ifdef DEBUG_ALL
  626.     printfT( "nhandles() returned %d\n", h );
  627. #endif
  628.     if (2*maxNntpThreads+8 > h) {
  629.         if (threadCntGiven)
  630.         areas.mailPrintf1( 1,"%s: not enough file handles for %d connected threads\n",
  631.                    progname, maxNntpThreads );
  632.         maxNntpThreads = (h-8) / 2;
  633.         if (threadCntGiven)
  634.         areas.mailPrintf1( 1,"%s: number of threads cut to %d (increase the -h setting in the EMXOPT\n\tenvironment variable in CONFIG.SYS, e.g. 'SET EMXOPT=-h40')\n",
  635.                    progname,maxNntpThreads );
  636.         if (maxNntpThreads < 1)
  637.         exit( EXIT_FAILURE );
  638.     }
  639.     }
  640. #endif
  641.     
  642.     openAreasAndStartTimer(argc,argv);
  643.  
  644. #if defined(OS2)  &&  defined(__MT__)
  645.     BEGINTHREAD( checkTransfer, NULL );
  646. #endif
  647.  
  648.     switch (mode) {
  649.     case RECEIVE:
  650.     if (doMail) {
  651.         if ( !getMail( pop3Info.host,pop3Info.user,pop3Info.passwd,pop3Info.port ))
  652.         retcode = EXIT_FAILURE;
  653.     }
  654.     if (doNews) {
  655.         if (doSummary) {
  656.         if ( !sumNews())
  657.             retcode = EXIT_FAILURE;
  658.         }
  659.         else {
  660.         if ( !getNews(newsStrategy))
  661.             retcode = EXIT_FAILURE;
  662.         }
  663.     }
  664.     break;
  665.  
  666.     case SEND:
  667.     if ( !sendReply())
  668.         retcode = EXIT_FAILURE;
  669.     break;
  670.  
  671.     case CATCHUP:
  672.     if ( !catchupNews(catchupCount))
  673.         retcode = EXIT_FAILURE;
  674.     break;
  675.     }
  676.  
  677.     stopTimerEtc( retcode );
  678.  
  679.     prepareAbort();
  680.  
  681.     if (retcode != EXIT_SUCCESS)
  682.     areas.forceMail();
  683.     areas.closeAll();
  684.  
  685.     assert( _heapchk() == _HEAPOK );
  686.     
  687.     exit( retcode );
  688. }   // main
  689.