home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1997 April / PCO_04_97.ISO / filesbbs / os2 / vsoup127.arj / VSOUP127.ZIP / main.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-12  |  18.6 KB  |  697 lines

  1. //  $Id: main.cc 1.32 1997/02/12 10:04:54 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@ibm.net.
  6. //
  7. //  This file is part of soup++ for OS/2.  Soup++ 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.7 (rg120297)"
  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/kill", homeDir);
  72. #else
  73.     sprintfT(newsrcFile, "%s/.newsrc", homeDir);
  74.     sprintfT(killFile, "%s/.kill", 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 kill file\n", STDERR_FILENO);
  328.     hputsT("  -l n     Kill articles longer than n lines\n", STDERR_FILENO);
  329.     hputsT("  -L n     Kill articles shorter than n lines\n", STDERR_FILENO );
  330.     hputsT("  -N file  Set newsrc file\n", STDERR_FILENO);
  331. #if defined(OS2)  &&  defined(__MT__)
  332.     hputsT("  -S n     News reading strategy [0..2, default 1]\n", STDERR_FILENO );
  333.     hprintfT( STDERR_FILENO,"  -t n     Number of threads [1..%d, standard: %d]\n",
  334.           MAXNNTPTHREADS,DEFNNTPTHREADS );
  335. #endif
  336.     hputsT("  -u       Create news summary\n", STDERR_FILENO);
  337.     hputsT("  -x       Do not process news Xref headers\n", STDERR_FILENO);
  338.     hputsT( "mail reading option:\n", STDERR_FILENO );
  339.     hputsT("  -D       force deletion of mail on POP3 server on each message\n", STDERR_FILENO );
  340.  
  341.     assert( _heapchk() == _HEAPOK );
  342.  
  343.     areas.forceMail();
  344.     areas.closeAll();
  345.  
  346.     assert( _heapchk() == _HEAPOK );
  347.  
  348.     exit( EXIT_FAILURE );
  349. }   // usage
  350.  
  351.  
  352.  
  353. static void parseCmdLine( int argc, char **argv, int doAction )
  354. {
  355.     int c;
  356.     int i;
  357.  
  358.     optind = 0;
  359.     while ((c = getopt(argc, argv, "?ac::Dh:iK:k:l:L:MmN:nrsS:t:T:ux")) != EOF) {
  360.     if (!doAction) {
  361. #ifdef OS2
  362.         if (c == 'i')
  363.         doIni = 0;
  364. #endif
  365.     }
  366.     else {
  367.         switch (c) {
  368.         case '?':
  369.             usage( NULL );
  370.             break;
  371.         case 'a':
  372.             doNewGroups = 1;
  373.             break;
  374.         case 'c':
  375.             mode = CATCHUP;
  376.             if (optarg != NULL) {
  377.             catchupCount = atoi(optarg);
  378.             if (catchupCount < 0)
  379.                 catchupCount = 0;
  380.             }
  381.             else
  382.             catchupCount = 10;
  383.             break;
  384.         case 'D':
  385.             forceMailDelete = 1;
  386.             break;
  387.         case 'h':
  388.             homeDir = optarg;
  389.             setFiles();
  390.             break;
  391. #ifdef OS2
  392.         case 'i':
  393.             break;
  394. #endif
  395.         case 'K':
  396.             strcpy(killFile, optarg);
  397.             killFileOption = 1;
  398.             break;
  399.         case 'k':
  400.             maxBytes = atol(optarg) * 1000L;
  401.             break;
  402.         case 'l':
  403.             maxLines = atoi(optarg);
  404.             break;
  405.         case 'L':
  406.             minLines = atoi(optarg);
  407.             break;
  408.         case 'M':
  409.             areas.forceMail();
  410.             break;
  411.         case 'm':
  412.             doMail = 0;
  413.             break;
  414.         case 'N':
  415.             strcpy(newsrcFile, optarg);
  416.             break;
  417.         case 'n':
  418.             doNews = 0;
  419.             break;
  420.         case 'r':
  421.             readOnly = 1;
  422.             break;
  423.         case 's':
  424.             mode = SEND;
  425.             break;
  426. #if defined(OS2)  &&  defined(__MT__)
  427.         case 'S':
  428.             newsStrategy = atoi(optarg);
  429.             break;
  430.         case 't':
  431.             maxNntpThreads = atoi(optarg);
  432.             if (maxNntpThreads < 1  ||  maxNntpThreads > MAXNNTPTHREADS)
  433.             usage( "ill num of threads %s",optarg );
  434.             threadCntGiven = 1;
  435.             break;
  436. #endif
  437.         case 'T':
  438.             minThroughput = atol(optarg);
  439.             break;
  440.         case 'u':
  441.             doNews = 1;
  442.             doSummary = 1;
  443.             break;
  444.         case 'x':
  445.             doXref = 0;
  446.             break;
  447.         default:
  448.             usage( NULL );
  449.         }
  450.     }
  451.     }
  452.  
  453.     //
  454.     //  get the URLs
  455.     //
  456.     if (doAction) {
  457.     for (i = optind;  i < argc;  i++) {
  458.         if (strnicmp("smtp://",argv[i],7) == 0)
  459.         getUrlInfo( argv[i]+7, smtpInfo );
  460.         else if (strnicmp("pop3://",argv[i],7) == 0)
  461.         getUrlInfo( argv[i]+7, pop3Info );
  462.         else if (strnicmp("nntp://",argv[i],7) == 0)
  463.         getUrlInfo( argv[i]+7, nntpInfo );
  464.         else
  465.         usage( "ill URL %s",argv[i] );
  466.     }
  467.     }
  468. }   // parseCmdLine
  469.  
  470.  
  471.  
  472. #ifdef OS2
  473. static void readTcpIni (void)
  474. {
  475.     HAB hab;
  476.     HINI hini;
  477.     char *etc;
  478.     char buf[BUFSIZ];
  479.     char curConnect[200];
  480.  
  481.     etc = getenv("ETC");
  482.     if (etc == NULL) {
  483.     hputsT( "Must set ETC\n", STDERR_FILENO );
  484.     exit( EXIT_FAILURE );
  485.     }
  486.     sprintfT(buf, "%s\\TCPOS2.INI", etc);
  487.  
  488.     hab = WinInitialize(0);
  489.     hini = PrfOpenProfile(hab, buf);
  490.     if (hini == NULLHANDLE) {
  491.     hprintfT( STDERR_FILENO, "cannot open profile %s\n", buf );
  492.     exit(EXIT_FAILURE);
  493.     }
  494.  
  495.     PrfQueryProfileString(hini, "CONNECTION", "CURRENT_CONNECTION", "",
  496.                           curConnect, sizeof(curConnect));
  497.  
  498.     PrfQueryProfileString(hini, curConnect, "POPSRVR", "", buf, sizeof(buf));
  499.     xstrdup( &pop3Info.host,buf );
  500.     PrfQueryProfileString(hini, curConnect, "POP_ID", "", buf, sizeof(buf));
  501.     xstrdup( &pop3Info.user,buf );
  502.     xstrdup( &smtpInfo.user,buf );
  503.     xstrdup( &nntpInfo.user,buf );
  504.     PrfQueryProfileString(hini, curConnect, "POP_PWD", "", buf, sizeof(buf));
  505.     xstrdup( &pop3Info.passwd,buf );
  506.     xstrdup( &smtpInfo.passwd,buf );
  507.     xstrdup( &nntpInfo.passwd,buf );    
  508.  
  509.     PrfQueryProfileString(hini, curConnect, "DEFAULT_NEWS", "", buf, sizeof(buf));
  510.     xstrdup( &nntpInfo.host,buf );
  511.  
  512.     PrfQueryProfileString(hini, curConnect, "MAIL_GW", "", buf, sizeof(buf));
  513.     xstrdup( &smtpInfo.host,buf );
  514.     
  515.     PrfCloseProfile(hini);
  516.     WinTerminate(hab);
  517.  
  518. #ifdef DEBUG
  519.     printfT( "TCPOS2.INI information:\n" );
  520.     printfT( "-----------------------\n" );
  521.     printfT( "nntpServer:   %s\n", nntpInfo.host );
  522.     printfT( "popServer:    %s\n", pop3Info.host );
  523.     printfT( "mailGateway:  %s\n", smtpInfo.host );
  524.     printfT( "-----------------------\n" );
  525. #endif
  526. }   // readTcpIni
  527. #endif
  528.  
  529.  
  530.  
  531. static void signalHandler( int signo )
  532. //
  533. //  Signal handling:
  534. //  -  abort the sockets (sockets are unblocked...)
  535. //  -  close the files
  536. //  -  output an error message
  537. //
  538. //  es ist sehr die Frage, ob man hier sprintfT etc verwenden darf, da nicht 100%
  539. //  klar ist, ob ein abgeschossener Thread die zugehörigen Semaphore freigibt!? (scheint aber so...)
  540. //
  541. {
  542.     //
  543.     //  if SIGINT will be received, consecutive reception of the signal
  544.     //  will be disabled.  Otherwise set handling to default
  545.     //  (e.g. SIGTERM twice will terminate also signalHandler())
  546.     //
  547.     signal( signo, (signo == SIGUSR1  ||  signo == SIGINT) ? SIG_IGN : SIG_DFL );
  548.     signal( signo, SIG_ACK );
  549.  
  550. #ifndef NDEBUG
  551.     printfT( "\nmain thread received signal %d\n",signo );
  552. #endif
  553.  
  554.     prepareAbort();
  555.  
  556.     //  durch's Abbrechen gibt es manchmal einen SIGSEGV der sub-threads, da sie
  557.     //  z.B. auf eine Datei zugreifen, die schon geschlossen wurde.
  558.     //  die Kinder müssen zuerst gekillt werden (aber wie??)
  559.     //  Holzhammer:  die Threads brechen bei SIGSEGV ab.  Die Sockets werden auf
  560.     //  NONBLOCK gestellt und lösen ein SIGUSR1 aus, wenn abgebrochen werden soll
  561.     //
  562.  
  563.     areas.mailException();          // otherwise semaphors could block forever
  564.     
  565.     areas.mailPrintf1( 1,"\n*** signal %d received ***\n\n",signo );
  566.  
  567.     stopTimerEtc( EXIT_FAILURE );
  568.  
  569.     areas.forceMail();          // generate status mail in case of signal reception
  570.     areas.closeAll();
  571.  
  572.     if ( !readOnly)
  573.     newsrc.writeFile();
  574.  
  575.     exit( EXIT_FAILURE );       // wird ein raise() gemacht, so werden die exit-Routinen nicht aufgerufen (z.B. files löschen)
  576. }   // signalHandler
  577.  
  578.  
  579.  
  580. int main( int argc, char **argv )
  581. {
  582.     int retcode = EXIT_SUCCESS;
  583.     char *s;
  584.     
  585. #ifdef DEBUG
  586.     setvbuf( stdout,NULL,_IONBF,0 );
  587. #endif
  588.  
  589. #ifdef OS2
  590.     if (_osmode != OS2_MODE) {
  591.     hprintfT( STDERR_FILENO,"sorry, DOS not sufficient...\n" );
  592.     exit( EXIT_FAILURE );
  593.     }
  594. #endif
  595.     
  596.     signal(SIGINT,   signalHandler );     // ^C
  597.     signal(SIGBREAK, signalHandler );     // ^Break
  598.     signal(SIGHUP,   signalHandler );     // hang up
  599.     signal(SIGPIPE,  signalHandler );     // broken pipe
  600.     signal(SIGTERM,  signalHandler );     // kill (läßt der sich doch catchen?)
  601.     signal(SIGUSR1,  SIG_IGN );           // ignore this signal in the main thread (which should not be aborted...)
  602.     
  603.     progname = strrchr(argv[0], '\\');
  604.     if (progname == NULL)
  605.     progname = argv[0];
  606.     else
  607.     ++progname;
  608.  
  609.     //
  610.     //  get some environment vars (HOME, NNTPSERVER)
  611.     //
  612.     parseCmdLine(argc, argv, 0);    // only get doIni (-i)
  613. #ifdef OS2
  614.     if (doIni)
  615.     readTcpIni();
  616. #endif
  617.     if ((homeDir = getenv("HOME")) == NULL)
  618.     homeDir = ".";
  619.     if ((s = getenv("NNTPSERVER")) != NULL)
  620.     getUrlInfo( getenv("NNTPSERVER"), nntpInfo );
  621.     setFiles();
  622.     parseCmdLine(argc, argv, 1);
  623.     
  624.     assert( _heapchk() == _HEAPOK );
  625.  
  626.     //
  627.     //  check the number of free file handles
  628.     //
  629. #ifndef HANDLEERR
  630.     if (mode == RECEIVE  &&  doNews) {
  631.     int h = nhandles(150);    // maximum 150 handles
  632.  
  633. #ifdef DEBUG_ALL
  634.     printfT( "nhandles() returned %d\n", h );
  635. #endif
  636.     if (2*maxNntpThreads+8 > h) {
  637.         if (threadCntGiven)
  638.         areas.mailPrintf1( 1,"%s: not enough file handles for %d connected threads\n",
  639.                    progname, maxNntpThreads );
  640.         maxNntpThreads = (h-8) / 2;
  641.         if (threadCntGiven)
  642.         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",
  643.                    progname,maxNntpThreads );
  644.         if (maxNntpThreads < 1)
  645.         exit( EXIT_FAILURE );
  646.     }
  647.     }
  648. #endif
  649.     
  650.     openAreasAndStartTimer(argc,argv);
  651.  
  652. #if defined(OS2)  &&  defined(__MT__)
  653.     BEGINTHREAD( checkTransfer, NULL );
  654. #endif
  655.  
  656.     switch (mode) {
  657.     case RECEIVE:
  658.     if (doMail) {
  659.         if ( !getMail( pop3Info.host,pop3Info.user,pop3Info.passwd,pop3Info.port ))
  660.         retcode = EXIT_FAILURE;
  661.     }
  662.     if (doNews) {
  663.         if (doSummary) {
  664.         if ( !sumNews())
  665.             retcode = EXIT_FAILURE;
  666.         }
  667.         else {
  668.         if ( !getNews(newsStrategy))
  669.             retcode = EXIT_FAILURE;
  670.         }
  671.     }
  672.     break;
  673.  
  674.     case SEND:
  675.     if ( !sendReply())
  676.         retcode = EXIT_FAILURE;
  677.     break;
  678.  
  679.     case CATCHUP:
  680.     if ( !catchupNews(catchupCount))
  681.         retcode = EXIT_FAILURE;
  682.     break;
  683.     }
  684.  
  685.     stopTimerEtc( retcode );
  686.  
  687.     prepareAbort();
  688.  
  689.     if (retcode != EXIT_SUCCESS)
  690.     areas.forceMail();
  691.     areas.closeAll();
  692.  
  693.     assert( _heapchk() == _HEAPOK );
  694.     
  695.     exit( retcode );
  696. }   // main
  697.