home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / comms / network / grn1src.lha / grn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-07  |  46.1 KB  |  1,345 lines

  1. #include        "defs.h"
  2. #include        "memalloc.h"
  3. #include        "headers.h"
  4.  
  5. #include        <stdarg.h>
  6.  
  7. // #define PROCDEBUG
  8.  
  9. #ifdef PROCDEBUG
  10. #define D(x)    printf x
  11. #else
  12. #define D(x)
  13. #endif
  14.  
  15. extern char *FileNameToNewsGroup (char *filename);      /* IMPORT */
  16. extern char *NewsGroupToFileName (char *newsgroup);     /* IMPORT */
  17. extern int  BuildHierarchicalList (void);               /* IMPORT */
  18.  
  19. int hierarchical = 0;                                   /* EXPORT */
  20.             /* should be set by ONLY SetHierarchical() */
  21. int subscribe_mode = 0;
  22.             /* subscribe to new groups first! */
  23. char **subscribe_list;
  24.             /* list of new newsgroups to subscribe to */
  25. int subscribe_count;
  26.             /* how many in the list */
  27. int update_only_mode = 0;
  28.             /* only update grnrc file, then exit. No windows, no nothing. */
  29.  
  30. ULONG   grnrcVersion = '1.20';
  31. UWORD   windowHeight;
  32. UWORD   wrapCol = 82;                           // selectable wrap point for articles
  33.  
  34. /************************************************************************/
  35.  
  36. FILEREQ         *saveReq = 0;
  37. FILEREQ         *publishReq = 0;
  38.  
  39. static MPORT    *port = 0;
  40. char            userName[256], grnrcName[256];
  41. char            newsEditor[256], mailEditor[256];
  42. char            postNews[256], sendMail[256];
  43. char            uunews[256] = "UUNEWS:";
  44. char            uulib[256] = "UULIB:";
  45. char            uuspool[256] = "UUSPOOL:";
  46. char            logfile[256] = "";
  47.  
  48. BOOL            treeDirty = 0;
  49.  
  50. LIST            groupList;
  51.  
  52. LOCK            lock = 0;
  53. FIB             *fib = 0;
  54.  
  55. WINDOW          *mainWindow = 0;
  56.  
  57. UWORD           mode = GROUPS_MODE;
  58.  
  59. void ClearWindow (void)
  60. {
  61.         WORD    x, y, x1, y1;
  62.  
  63.         x  = mainWindow->BorderLeft;
  64.         y  = mainWindow->BorderTop;
  65.         x1 = mainWindow->Width - mainWindow->BorderRight - 1;
  66.         y1 = mainWindow->Height - mainWindow->BorderBottom - 1;
  67.  
  68.         SetAPen( mainWindow->RPort, 0);
  69.         SetDrMd( mainWindow->RPort, JAM1 );
  70.         RectFill( mainWindow->RPort, x, y, x1, y1 );
  71.  
  72.         RefreshWindowFrame (mainWindow);
  73.         return;
  74. }
  75.  
  76. void    CloseMain (void)
  77. {
  78.         if (publishReq) {
  79.                 FreeFileRequest (publishReq);
  80.                 publishReq = 0;
  81.         }
  82.         if (saveReq) {
  83.                 FreeFileRequest (saveReq);
  84.                 saveReq = 0;
  85.         }
  86.         if (fib) {
  87.                 FreeDosObject (DOS_FIB, (void *) fib);
  88.                 fib = 0;
  89.         }
  90.         if (lock) {
  91.                 UnLock (lock);
  92.                 lock = 0;
  93.         }
  94.         if (mainWindow) {
  95.                 CloseWindow (mainWindow);
  96.                 mainWindow = 0;
  97.         }
  98.         return;
  99. }
  100.  
  101. /*
  102.  * void Abort(void);
  103.  *
  104.  * Synopsis:
  105.  *      Cleanup and exit.  Can be called anywhere, anytime, including from
  106.  *      the debugger by setting PC = Abort.
  107.  */
  108. long    abort_code = 0;
  109.  
  110. void    Abort (void)
  111. {
  112.         CloseGroups ();
  113.         CloseMain ();
  114.         if (port) {
  115.                 DeletePort (port);
  116.                 port = 0;
  117.         }
  118.         CloseSystem ();
  119.         exit (abort_code);
  120. }
  121.  
  122. /*
  123.  * void panic0(v, s,a1,a2,a3,a4);
  124.  * ULONG        v;
  125.  * char         *s;
  126.  * ULONG        a1,a2,a3,a4;
  127.  *
  128.  * Synopsis:
  129.  *      Anywhere you use:
  130.  *              v = (some function);
  131.  *              if (!v) {
  132.  *                      printf("some string");
  133.  *                      Abort();
  134.  *              }
  135.  *      You can use:
  136.  *              v = (some function);
  137.  *              panic0(v, "some string");
  138.  *      The string and args (a1,a2,a3,a4) are passed to printf...
  139.  */
  140. void    panic0 (APTR v, const char *s, ...)
  141. {
  142.         FILE    *outfp;
  143.         va_list va;
  144.  
  145.         va_start (va, s);
  146.         if (v)
  147.                 return;
  148.         printf ("Panic: ");
  149.         _pfmt (s, va, fwrite, stdout);
  150.         printf ("\n");
  151.         if (logfile [0] == '\0')
  152.                 strcpy (logfile, "UUSPOOL:logfile");
  153.         outfp = fopen (logfile, "a");
  154.         if (outfp) {
  155.                 fprintf (outfp, "GRn panic: ");
  156.                 _pfmt (s, va, fwrite, outfp);
  157.                 fprintf (outfp, "\n");
  158.                 fclose (outfp);
  159.         }
  160.         va_end (va);
  161.         abort_code = 999;
  162.         Abort ();
  163.         /* NOTREACHED */
  164.         return;
  165. }
  166.  
  167. void    panic (const char *s, ...)
  168. {
  169.         FILE    *outfp;
  170.         va_list va;
  171.  
  172.         va_start (va, s);
  173.         printf ("Panic: ");
  174.         printf (s, va);
  175.         _pfmt (s, va, fwrite, stdout);
  176.         printf ("\n");
  177.         if (logfile [0] == '\0')
  178.                 strcpy (logfile, "UUSPOOL:logfile");
  179.         outfp = fopen(logfile, "a");
  180.         if (outfp) {
  181.                 fprintf (outfp, "GRn panic: ");
  182.                 _pfmt (s, va, fwrite, outfp);
  183.                 fprintf (outfp, "\n");
  184.                 fclose (outfp);
  185.         }
  186.         va_end (va);
  187.         abort_code = 999;
  188.         Abort ();
  189.         /* NOTREACHED */
  190.         return;
  191. }
  192.  
  193. /************************************************************************/
  194.  
  195. UBYTE   *mbuf = 0, *mbufp, *mbufe;
  196.  
  197. void    mclose (void)
  198. {
  199.         if (mbuf) {
  200.                 free (mbuf);
  201.                 mbuf = 0;
  202.         }
  203.         return;
  204. }
  205.  
  206. BOOL    mopen (char *fn)
  207. {
  208.         int     fd;
  209.         ULONG   size;
  210.  
  211.         mclose ();
  212.         fd = open (fn, O_READ);
  213.         if (fd < 0)
  214.                 return 0;
  215.  
  216.         size = lseek (fd, 0, 2);
  217.         lseek (fd, 0, 0);
  218.         mbuf = (UBYTE *) malloc (size);
  219.         if (!mbuf) {
  220.                close (fd);
  221.                return 0;
  222.         }
  223.         read (fd, mbuf, size);
  224.         close (fd);
  225.         mbufp = mbuf;
  226.         mbufe = &mbufp[size];
  227.         return 1;
  228. }
  229.  
  230. BOOL    mread (UBYTE *buf, ULONG size)
  231. {
  232.         ULONG   i;
  233.  
  234.         if (!mbuf || mbufp == mbufe)
  235.                 return 0;
  236.         for (i = 0; i < size; i++)
  237.                 *buf++ = (mbufp == mbufe) ? 0 : *mbufp++;
  238.         return 1;
  239. }
  240.  
  241. BOOL    mgets (UBYTE *buf)
  242. {
  243.         if (mbufp == mbufe)
  244.                 return 0;
  245.         while (mbufp != mbufe && (*buf++ = *mbufp++));
  246.         *buf = '\0';
  247.         return 1;
  248. }
  249.  
  250. /************************************************************************/
  251.  
  252. BOOL    EmptyList (LIST *list)
  253. {
  254.         if (list->lh_TailPred == (NODE *)list)
  255.                 return !0;
  256.         return 0;
  257. }
  258.  
  259. NODE    *FindListItem (LIST *list, short num)
  260. {
  261.         NODE    *np;
  262.  
  263.         for (np = list->lh_Head; np->ln_Succ; np = np->ln_Succ) {
  264.                 if (!num)
  265.                         return np;
  266.                 num--;
  267.         }
  268.         return 0;
  269. }
  270.  
  271. void    SortList (LIST *list, short col)
  272. {
  273.         LIST    tmp;
  274.         register NODE *np;
  275.         register NODE *np2;
  276.         register char *pname;
  277.  
  278.         if (EmptyList (list))
  279.                 return;
  280.         NewList (&tmp);
  281.  
  282.         while (!EmptyList (list)) {
  283.                 np = RemHead (list);
  284.                 if (EmptyList (&tmp)) {
  285.                         AddHead (&tmp, np);
  286.                 }
  287.                 else {
  288.                         pname = &np->ln_Name [col];
  289.                         if (strcmp (pname, &tmp.lh_Head->ln_Name [col]) < 0) {
  290.                                 AddHead (&tmp, np);
  291.                         }
  292.                         else if (strcmp (pname, &tmp.lh_TailPred->ln_Name [col]) > 0) {
  293.                                 AddTail (&tmp, np);
  294.                         }
  295.                         else {
  296.                                 for (np2 = tmp.lh_Head; np2->ln_Succ; np2 = np2->ln_Succ) {
  297.                                         if (strcmp (pname, &np2->ln_Name [col]) < 0) {
  298.                                                 Insert (&tmp, np, np2->ln_Pred);
  299.                                                 break;
  300.                                         }
  301.                                 }
  302.                         }
  303.                 }
  304.  
  305.         }
  306.         NewList (list);
  307.         while (!EmptyList (&tmp)) {
  308.                 np = RemHead (&tmp);
  309.                 AddTail (list, np);
  310.         }
  311.         return;
  312. }
  313.  
  314. /************************************************************************/
  315.  
  316. void    FixName (char *dst, char *src)
  317. {
  318.  
  319. #define CHK_SIZE_ERR(x,p)  if ((int) (p) >= 512) OutputStrings (2, "FixName error (", itoa (x), ") string too big: ", itoa ((int) (dst - d)), " bytes '", d, "'\n", NULL);
  320.  
  321.         short   i, j;
  322.         BOOL    ltFlag = 0;
  323.         char    *d = dst;
  324.         short   pcount = 0;
  325.  
  326.         // D (("FixName: enter\n"));
  327.  
  328.         for (i = 0; src [i]; i++)
  329.                 if (src [i] == '<') {
  330.                         ltFlag = 1;
  331.                         break;
  332.                 }
  333.  
  334.         if (*src == '"') {
  335.                 // From: "Some Quoted Horror" <mbs@adastra.cvl.va.us>
  336.                 for (j = 1; src [j] && src [j] != '"'; j++)
  337.                         *dst++ = src [j];
  338.                 *dst++ = '\0';
  339.                 CHK_SIZE_ERR (1, (dst - d));
  340.                 return;
  341.         }
  342.         if (*src == '<') {
  343.                 // From: <mbs@adastra.cvl.va.us> (Michael B. Smith)
  344.                 //          -or-
  345.                 // From: <mbs@adastra.cvl.va.us> Michael B. Smith
  346.                 // This piece could be better....
  347.                 for (j = 1; src [j] && src [j] != '@' && src [j] != '>'; j++) {
  348.                         if (src [j] == '.')
  349.                                 *dst++ = ' ';
  350.                         else
  351.                                 *dst++ = src [j];
  352.                 }
  353.                 *dst++ = '\0';
  354.                 CHK_SIZE_ERR (2, (dst - d));
  355.                 return;
  356.         }
  357.         for (j = 0; src [j]; j++) {
  358.                 if (src [j] == '<') {
  359.                         if (!j) {
  360.                                 OutputStrings (2, "Should never happen\n", NULL);
  361.                                 CHK_SIZE_ERR (3, strlen (src));
  362.                                 strncpy (dst, src, 512);
  363.                                 return;
  364.                         }
  365.                         else {
  366.                                 // From: Michael B. Smith <mbs@adastra.cvl.va.us>
  367.                                 for (i = 0; i < j; i++)
  368.                                         *dst++ = *src++;
  369.                                 *dst++ = '\0';
  370.                                 CHK_SIZE_ERR (4, (dst - d));
  371.                                 return;
  372.                         }
  373.                 }
  374.  
  375.                 // example nested parens:  (Blonder (The one and Only :))
  376.                 if (src[j] == '(' && !ltFlag) {
  377.                         pcount++;
  378.                         j++;
  379.                         while (src [j] && pcount) {
  380.                                 switch (src [j]) {
  381.                                         case ')':
  382.                                                 pcount--;
  383.                                                 if (pcount)
  384.                                                         *dst++ = src [j];
  385.                                                 j++;
  386.                                                 break;
  387.                                         case '(':
  388.                                                 pcount++;
  389.                                         default:
  390.                                                 *dst++ = src [j++];
  391.                                                 break;
  392.                                 }
  393.                         }
  394.                         *dst++ = '\0';
  395.                         CHK_SIZE_ERR (5, (dst - d));
  396.                         return;
  397.                 }
  398.         }
  399.         j = -1;
  400.         for (i = 0; src [i]; i++)
  401.                 if (src [i] == '!')
  402.                         j = i;
  403. #if 1
  404.         if (j < 0)
  405.                 d = src;
  406.         else
  407.                 d = &src [j + 1];
  408.  
  409.         while (*d && *d != ',' && *d != '@' && *d !='%')
  410.                 *dst++ = *d++;
  411.         *dst++ = '\0';
  412. #else
  413.         if (j != -1) {
  414.                 j++;
  415.                 while (src [j] && src [j] != ',' && src [j] != '@')
  416.                         *dst++ = src [j++];
  417.                 *dst++ = '\0';
  418.         }
  419.         else {
  420.                 while (*src && *src != '%' && *src != '@')
  421.                         *dst++ = *src++;
  422.                 *dst++ = '\0';
  423.         }
  424. #endif
  425.         CHK_SIZE_ERR (6, (dst - d));
  426.         // D (("FixName: exit\n"));
  427.         return;
  428. }
  429.  
  430. #undef CHK_SIZE_ERR
  431.  
  432. /************************************************************************/
  433.  
  434. void SetHierarchical (void)
  435. {
  436.         BPTR lock;
  437.  
  438.         // This routine finds out if we are hierarchical or not
  439.         // and sets the global variable 'hierarchical' appropriately.
  440.         //
  441.         // The way things are set up, this causes a slight performance
  442.         // hit on non-hierarchical systems.
  443.         //
  444.         // uses the global fib
  445.  
  446.         lock = Lock (uunews, SHARED_LOCK);
  447.         panic0 ((APTR) lock, "Lock (%s) failed", uunews);
  448.  
  449.         hierarchical = 1; /* presume globally true, until proven otherwise */
  450.         Examine (lock, fib);
  451.         while (ExNext (lock, fib)) {
  452.                 if (fib->fib_DirEntryType < 0)
  453.                         continue;
  454.                 if (hierarchical && strchr (fib->fib_FileName, '.') == NULL) {
  455.                         /* This is the first directory (ALL modern newsgroups */
  456.                         /* have more than one level. So if the structure is   */
  457.                         /* flat, and it WASNT hierarchical, we wouldn't get   */
  458.                         /* here because it would have a period in it). If it  */
  459.                         /* is hierarchical, then do the hierarchical thing    */
  460.                         /* and then get out of here....as our initial guess   */
  461.                         /* was correct.                                       */
  462.  
  463.                         // unless this system is running C-News. <sigh>
  464.                         if (strcmp (fib->fib_FileName, "in.coming") == 0)
  465.                                 continue;
  466.                         if (strcmp (fib->fib_FileName, "out.going") == 0)
  467.                                 continue;
  468.  
  469.                         break;
  470.                 }
  471.                 hierarchical = 0;
  472.                 break;
  473.         }
  474.         UnLock (lock);
  475.  
  476.         return;
  477. }
  478.  
  479. /************************************************************************/
  480.  
  481. #define MOVE4(x)    { *p++ = ((x >> 24) & 0xff); *p++ = ((x >> 16) & 0xff); *p++ = ((x >> 8) & 0xff); *p++ = (x & 0xff); }
  482. #define MOVE2(x)    { *p++ = ((x >>  8) & 0xff); *p++ = (x & 0xff); }
  483. #define MOVE1(x)    { *p++ = (x & 0xff); }
  484. #define MOVESTR(x)  { p2 = x; while (*p2) *p++ = *p2++; *p++ = '\0'; }
  485.  
  486. void    WriteNewsTree (void)
  487. {
  488.         int     fd;
  489.         int     do_it_the_hard_way = 0;
  490.         ART     *ap;
  491.         GLIST   *gp;
  492.         UWORD   end = END;
  493.         char    *memoryfile;
  494.         register ULONG  pct;
  495.         register ULONG  artCount = 0;
  496.         register ULONG  groupSize = 0;
  497.         register ULONG  artSize = 0;
  498.         long    len;
  499.         long    offset;
  500.  
  501.         extern ULONG totalArticles;
  502.         extern ULONG totalGroups;
  503.  
  504.         D (("WriteNewsTree: enter\n"));
  505.  
  506.         if (!treeDirty)
  507.                 return;
  508.  
  509.         if ((fd = creat (grnrcName, 0660)) < 0) {
  510.                 // don't panic() since the user might can correct the problem!
  511.                 t_printf ("Can't open %s for output!!!!", grnrcName);
  512.                 D (("WriteNewsTreee: exit, can't open grnrc\n"));
  513.                 return;
  514.         }
  515.  
  516.         t_printf (mainWindow, "Building in-core copy of %s", grnrcName);
  517.  
  518.         for (gp = (GLIST *) groupList.lh_Head;
  519.              gp->node.ln_Succ;
  520.              gp = (GLIST *) gp->node.ln_Succ) {
  521.  
  522.                 groupSize += strlen (gp->groupName) + 11;
  523.  
  524.                 for (ap = (ART *)gp->artList.lh_Head;
  525.                      ap->node.ln_Succ;
  526.                      ap = (ART *)ap->node.ln_Succ) {
  527.  
  528.                         artSize += strlen (ap->from) +
  529.                                    strlen (ap->subject) + 8;
  530.                 }
  531.         }
  532.         // printf ("Memoryfile size = %d\n", groupSize + artSize);
  533.  
  534.         memoryfile = malloc (groupSize + artSize + 5);
  535.  
  536.         // Output the data. If we can't get enough memory, then output
  537.         // grnrc the old way.
  538.  
  539.         if (!memoryfile) {
  540.                 do_it_the_hard_way = 1;
  541.                 D (("WriteNewsTree: can't get memory\n"));
  542.         }
  543.         else {
  544.                 register char *p = memoryfile;
  545.                 register char *p2;
  546.  
  547.                 // t_printf (mainWindow, "Building in-core copy of your grnrc");
  548.  
  549.                 MOVE4 (grnrcVersion);
  550.  
  551.                 for (gp = (GLIST *) groupList.lh_Head;
  552.                      gp->node.ln_Succ;
  553.                      gp = (GLIST *) gp->node.ln_Succ) {
  554.  
  555.                         pct = (100 * artCount) / totalArticles;
  556.                         if (GuageRequest (pct, "Closing Down", "Building News Tree", "Wait"))
  557.                                 ;
  558.                         MOVESTR (gp->groupName);
  559.                         MOVE1   (gp->hideHeaders);
  560.                         MOVE1   (gp->hideRead);
  561.                         MOVE4   (gp->nextReceived);
  562.                         MOVE2   (gp->sortActive);
  563.                         SortArticlesByNumber (&gp->artList);
  564.                         for (ap = (ART *) gp->artList.lh_Head;
  565.                              ap->node.ln_Succ;
  566.                              ap = (ART *) ap->node.ln_Succ) {
  567.  
  568.                                 artCount++;
  569.                                 MOVE2   (ap->state);
  570.                                 MOVE4   (ap->filenum);
  571.                                 MOVESTR (ap->from);
  572.                                 MOVESTR (ap->subject);
  573.                         }
  574.                         MOVE2 (end);
  575.                 }
  576.                 // printf ("Built memoryfile\n");
  577.                 GuageRequest (1000, "Closing Down", "Building News Tree", "Wait");
  578.  
  579.                 t_printf (mainWindow, "Dumping News Tree to %s", grnrcName);
  580.  
  581.                 len = (long) (p - memoryfile);
  582.                 offset = 0;
  583.                 do {
  584.                         pct = write (fd, &memoryfile [offset], len);
  585.                         if (pct < 0) {
  586.                                 // shit.
  587.                                 t_printf (mainWindow, "Output failure. Trying again.");
  588.                                 D (("WriteNewsTree: write error\n"));
  589.                                 free (memoryfile);
  590.                                 memoryfile = 0;
  591.                                 close (fd);
  592.                                 fd = creat (grnrcName, 0660);
  593.                                 if (fd < 0) {
  594.                                         t_printf (mainWindow, "I give up. Try again later.");
  595.                                         D (("WriteNewsTree: exit, can't creat() grnrc after write error\n"));
  596.                                         return;
  597.                                 }
  598.                                 do_it_the_hard_way = 1;
  599.                                 len = 0;
  600.                                 break;
  601.                         }
  602.                         offset += pct;
  603.                         len -= pct;
  604.                 } while (len > 0);
  605.         }
  606.  
  607.         if (do_it_the_hard_way) {
  608.                 t_printf (mainWindow, "GRn - Writing News Tree to %s", grnrcName);
  609.                 write (fd, &grnrcVersion, 4);
  610.                 artCount = 0;
  611.  
  612.                 for (gp = (GLIST *) groupList.lh_Head;
  613.                      gp->node.ln_Succ;
  614.                      gp = (GLIST *) gp->node.ln_Succ) {
  615.  
  616.                         pct = (100 * artCount) / totalArticles;
  617.                         if (GuageRequest (pct, "Closing Down", "Writing News Tree", "Wait"))
  618.                                 ;
  619.                         write (fd, gp->groupName, strlen (gp->groupName)+1);
  620.                         write (fd, &gp->hideHeaders, 1);
  621.                         write (fd, &gp->hideRead, 1);
  622.                         write (fd, &gp->nextReceived, 4);
  623.                         write (fd, &gp->sortActive, 2);
  624.                         // sort the articles in this group by number
  625.                         SortArticlesByNumber (&gp->artList);
  626.                         for (ap = (ART *) gp->artList.lh_Head;
  627.                              ap->node.ln_Succ;
  628.                              ap = (ART *) ap->node.ln_Succ) {
  629.  
  630.                                 artCount++;
  631.                                 write (fd, &ap->state, 2);
  632.                                 write (fd, &ap->filenum, 4);
  633.                                 write (fd, ap->from, strlen (ap->from)+1);
  634.                                 write (fd, ap->subject, strlen (ap->subject)+1);
  635.                         }
  636.                         write(fd, &end, 2);
  637.                 }
  638.                 GuageRequest (1000, "Closing Down", "Writing News Tree", "Wait");
  639.         }
  640.  
  641.         if (memoryfile) {
  642. #if 1
  643.                 free (memoryfile);
  644. #else
  645.                 // this code is for debugging changes to the GRnRC format
  646.                 char buf [2];
  647.                 register char *p = memoryfile;
  648.                 int i;
  649.                 int er;
  650.  
  651.                 printf ("checking memoryfile against grnrc\n");
  652.                 if ((fd = open (grnrcName, O_RDONLY)) < 0) {
  653.                         printf ("Can't open grnrc for input!\n");
  654.                         free (memoryfile);
  655.                         return;
  656.                 }
  657.                 // this is slow, but effective
  658.                 er = 0;
  659.                 while (read (fd, buf, 1) > 0) {
  660.                         if (((*p) & 0xff) != (buf [0] & 0xff)) {
  661.                                 printf ("Mismatch. Byte %d, p = 0x%x, buf = 0x%x\n",
  662.                                             (int) (p - memoryfile), (*p) & 0xff, (buf [0] & 0xff));
  663.                                 er++;
  664.                                 break;
  665.                         }
  666.                         p++;
  667.                 }
  668.                 if (er == 0) {
  669.                         printf ("No errors in %d bytes!\n", (int) (p - memoryfile));
  670.                 }
  671.                 close (fd);
  672.                 free (memoryfile);
  673. #endif
  674.         }
  675.  
  676.         close (fd);
  677.         treeDirty = 0;
  678.  
  679.         D (("WriteNewsTree: exit\n"));
  680.         return;
  681. }
  682.  
  683. #undef MOVE1
  684. #undef MOVE2
  685. #undef MOVE4
  686. #undef MOVESTR
  687.  
  688. //
  689. // This routine builds an article (ART) entry. It gets the Subject and From
  690. // header out of the file.
  691. //
  692. ART *BuildART (const char *fname, const int num, const int state)
  693. {
  694.         ART     *ap;
  695.         char    *subject;
  696.         static char work [512];
  697.  
  698.         From = NULL;
  699.         Subject = NULL;
  700.         if (ScanAndLoadHeaders (fname, HEADER_FROM | HEADER_SUBJECT, 0) < 0) {
  701.                 return NULL;
  702.         }
  703.         subject = Subject ? Subject : "<No Subject Found>";
  704.         if (From)
  705.                 FixName (work, From);
  706.         else
  707.                 strcpy (work, "<No From Found>");
  708.  
  709.         ap = AllocART (work, subject);
  710.         ap->state = state;
  711.         ap->filenum = num;
  712.  
  713.         return ap;
  714. }
  715. //
  716. // This routine scans uunews: and finds all the newsgroups and articles.
  717. // The news tree is built from scratch and all articles are marked as unread.
  718. //
  719. void    BuildNewsTree (void)
  720. {
  721.         ART     *ap;
  722.         GLIST   *gp;
  723.         UWORD   num;
  724.         char    groupName[256], filename[256], temp[512];
  725.         BPTR    fh;
  726.         char    *p;
  727.  
  728.         if (subscribe_mode) {
  729.                 int i;
  730.  
  731.                 t_printf (mainWindow, "GRn - Building New Subscription Lists");
  732.  
  733.                 for (i = 0; i < subscribe_count; i++) {
  734.                         p = subscribe_list [i + 2];
  735.                         strcpy (filename, uunews);
  736.                         AddPart (filename, NewsGroupToFileName (p), 256);
  737.                         if (lock = Lock (filename, SHARED_LOCK)) {
  738.                                 // should we Examine() to make sure it's a
  739.                                 // directory? Naahhh.
  740.                                 // FIXME - validate newsgroup name from
  741.                                 // uulib:NewsGroups
  742.                                 gp = AllocGLIST (p, p);
  743.                                 AddTail (&groupList, (NODE *) gp);
  744.                                 UnLock (lock);
  745.                                 lock = 0;
  746.                         }
  747.                         else {
  748.                                 OutputStrings (2, "Newsgroup doesn't exist: ", p, "\n", NULL);
  749.                         }
  750.                 }
  751.         }
  752.         else {
  753.                 t_printf (mainWindow, "GRn - Building News Tree...");
  754.  
  755.                 if (hierarchical) {
  756.                         if (BuildHierarchicalList () < 0)
  757.                                 panic0 (0, "There was an error building the newsgroup list\n");
  758.                 }
  759.                 else {
  760.                         lock = Lock (uunews, SHARED_LOCK);
  761.                         panic0 ((APTR)lock, "Lock(%s) failed", uunews);
  762.  
  763.                         Examine (lock, fib);
  764.                         while (ExNext (lock, fib)) {
  765.                                 if (fib->fib_DirEntryType < 0)
  766.                                         continue;
  767.                                 // ignore C-News control directories
  768.                                 if (strcmp (fib->fib_FileName, "in.coming") == 0)
  769.                                         continue;
  770.                                 if (strcmp (fib->fib_FileName, "out.going") == 0)
  771.                                         continue;
  772.  
  773.                                 gp = AllocGLIST (fib->fib_FileName, fib->fib_FileName);
  774.                                 AddTail (&groupList, (NODE *) gp);
  775.                         }
  776.                         UnLock (lock);
  777.                         lock = 0;
  778.                 }
  779.         }
  780.  
  781.         SortList (&groupList, 0);
  782.  
  783.         gp = (GLIST *)groupList.lh_Head;
  784.  
  785.         for (; gp->node.ln_Succ; gp=(GLIST *)gp->node.ln_Succ) {
  786.                 t_printf (mainWindow, "GRn - Scanning %s...", gp->groupName);
  787.                 gp->articles = 0;
  788.                 gp->unread = 0;
  789.                 strcpy (groupName, uunews);
  790.                 AddPart (groupName, NewsGroupToFileName (gp->groupName), 256);
  791.                 lock = Lock (groupName, SHARED_LOCK);
  792.                 if (!lock) {
  793.                         // could fail for a variety of reasons. We don't care.
  794.                         OutputStrings (2, "Lock() failed on ", groupName, "\n", NULL);
  795.                         continue;
  796.                 }
  797.                 strcpy (filename, groupName);
  798.                 strcat (filename, "/.next");
  799.                 if (fh = Open (filename, MODE_OLDFILE)) {
  800.                         Read (fh, temp, 512);
  801.                         Close (fh);
  802.                         gp->nextReceived = atoi (temp);
  803.                 }
  804.                 else {
  805.                         gp->nextReceived = 0;
  806.                 }
  807.                 gp->hideHeaders = !0;
  808.                 gp->hideRead = !0;
  809.                 gp->sortActive = 0;
  810.                 NewList (&gp->artList);
  811.                 Examine (lock, fib);
  812.                 while (ExNext (lock, fib)) {
  813.                         // FIXME - across a network this could be a SOFTLINK
  814.                         if (fib->fib_DirEntryType > 0)
  815.                                 continue;
  816.                         if (!(num = atoi (fib->fib_FileName)))
  817.                                 continue;
  818.  
  819.                         CopyStrings (filename, groupName, "/", fib->fib_FileName, NULL);
  820.                         ap = BuildART (filename, num, UNREAD);
  821.                         if (!ap) {
  822.                                 OutputStrings (2, "fopen() failed on ", filename, "\n", NULL);
  823.                                 continue;
  824.                         }
  825.                         AddTail (&gp->artList, (NODE *) ap);
  826.  
  827.                         gp->articles++;
  828.                         gp->unread++;
  829.                 }
  830.                 sprintf(gp->header, "%-40.40s %6d articles %6d UnRead", gp->groupName, gp->articles, gp->unread);
  831.         }
  832.         UnLock (lock);
  833.         lock = 0;
  834.         treeDirty = 1;
  835.         return;
  836. }
  837.  
  838. void    ReadNewsTree (void) {
  839.         ART     *ap;
  840.         GLIST   *gp;
  841.         char    temp [256], subj [256];
  842.         UWORD   endTest;
  843.         ULONG   fileNum;
  844.         ULONG   pct;
  845.  
  846.         t_printf (mainWindow, "GRn - Reading News Tree...");
  847.         while (1) {
  848.                 if (!mgets (temp))
  849.                         break;
  850.                 t_printf (mainWindow, "GRN - Reading News Tree...(%s)", temp);
  851.                 gp = AllocGLIST (temp, NULL);
  852.                 AddTail (&groupList, (NODE *)gp);
  853.                 NewList (&gp->artList);
  854.                 gp->articles = 0;
  855.                 gp->unread = 0;
  856.                 mread (&gp->hideHeaders, 1);
  857.                 mread (&gp->hideRead, 1);
  858.                 mread (&gp->nextReceived, 4);
  859.                 mread (&gp->sortActive, 2);
  860.                 pct = (100 * (ULONG)(mbufp - mbuf)) / (ULONG)(mbufe - mbuf);
  861.                 if (GuageRequest (pct, "Initializing", "Setting up News Tree", "Abort"))
  862.                         Abort ();
  863.                 while (1) {
  864.                         mread (&endTest, 2);
  865.                         if (endTest == END)
  866.                                 break;
  867.                         mread (&fileNum, 4);
  868.                         mgets (temp);  // From: header
  869.                         mgets (subj);  // Subject: header
  870.  
  871.                         ap = AllocART (temp, subj);
  872.                         ap->state = endTest;
  873.                         ap->filenum = fileNum;
  874.  
  875.                         AddTail (&gp->artList, (NODE *) ap);
  876.                         gp->articles++;
  877.                         if (ap->state == UNREAD || ap->state == NEW)
  878.                                 gp->unread++;
  879.                 }
  880.                 sprintf (gp->header, "%-40.40s %6d articles %6d UnRead",
  881.                                      gp->groupName, gp->articles, gp->unread);
  882.         }
  883.         mclose ();
  884.         return;
  885. }
  886.  
  887. void    UpdateNewsTree (void) {
  888.         register GLIST   *gp;           // the current group pointer
  889.         register ART     *ap;           // the current article pointer
  890.         register ART     *save_ap;      // save the pointer while we clean up
  891.         long    num, last;              // article number
  892.         char    fname [256], work [256];
  893.         char    *ptr;                   // points to the end of the constant part of fname
  894.         BPTR    lock;
  895.         BPTR    fh;
  896.  
  897.         // FIXME - we should CurrentDir() to UUNEWS:, and do all operations
  898.         // relative to there.
  899.  
  900.         // for each group
  901.         for (gp=(GLIST *)groupList.lh_Head; gp->node.ln_Succ; gp = (GLIST *)gp->node.ln_Succ) {
  902.                 t_printf (mainWindow, "GRn - Pruning %s", gp->groupName);
  903.                 strcpy (fname, uunews);
  904.                 AddPart (fname, NewsGroupToFileName (gp->groupName), 256);
  905.                 ptr = fname + strlen (fname);
  906.                 // scan through list and check to see which files
  907.                 // are still there!
  908.                 for (ap = (ART *)gp->artList.lh_Head; ap->node.ln_Succ; ap = (ART *)ap->node.ln_Succ) {
  909.                         *ptr = '\0';
  910.                         strcpy (work, itoa (ap->filenum));
  911.                         AddPart (fname, work, 256);
  912.                         if (lock = Lock (fname, SHARED_LOCK)) {
  913.                                 UnLock (lock);
  914.                                 break; // as soon as we find one, quit looking
  915.                                        // for them not to be there...
  916.                         }
  917.                         else {
  918.                                 if (ap->state == UNREAD)
  919.                                         gp->unread--;
  920.                                 gp->articles--;
  921.                                 save_ap = (ART *) ap->node.ln_Pred;
  922.                                 Remove ((NODE *) ap);
  923.                                 FreeART (ap);
  924.                                 ap = save_ap;
  925.                                 treeDirty = 1;
  926.                         }
  927.                 }
  928.                 // Find new articles, mark as unread!
  929.                 t_printf (mainWindow, "GRn - Getting new articles for %s",
  930.                                       gp->groupName);
  931.                 *ptr = '\0';
  932.                 AddPart (fname, ".next", 256);
  933.                 if (fh = Open (fname, MODE_OLDFILE)) {
  934.                         Read (fh, work, 256);
  935.                         Close (fh);
  936.                         last = atoi (work);
  937.                 }
  938.                 else {
  939.                         last = 1000000;
  940.                 }
  941.                 for (num = gp->nextReceived; num < last; num++) {
  942.                         *ptr = '\0';
  943.                         strcpy (work, itoa (num));
  944.                         AddPart (fname, work, 256);
  945.  
  946.                         ap = BuildART (fname, num, UNREAD);
  947.                         if (!ap) {
  948.                                 if (last == 1000000)
  949.                                         break;
  950.                                 continue;
  951.                         }
  952.  
  953.                         AddTail (&gp->artList, (NODE *) ap);
  954.                         gp->articles++;
  955.                         gp->unread++;
  956.                         treeDirty = 1;
  957.                 }
  958.                 sprintf (gp->header, "%-40.40s %6d articles %6d UnRead", gp->groupName, gp->articles, gp->unread);
  959.                 if (gp->nextReceived != last) {
  960.                         gp->nextReceived = last;
  961.                         treeDirty = 1;
  962.                 }
  963.         }
  964.         return;
  965. }
  966.  
  967. void    CheckNews (void) {
  968.         ULONG   testver = 0x0a0a5050;
  969.  
  970.         SetHierarchical ();
  971.         if (!mopen (grnrcName)) {
  972.                 BuildNewsTree ();
  973.                 return;
  974.         }
  975.         mread (&testver, 4);
  976.         if (testver != grnrcVersion)
  977.                 panic ("grnrc is wrong version, delete it and run GRn again");
  978.  
  979.         if (subscribe_mode)
  980.                 BuildNewsTree ();
  981.  
  982.         if (GuageRequest (0, "Initializing", "Setting up News Tree", "Abort"))
  983.                 Abort ();
  984.         ReadNewsTree ();
  985.         GuageRequest (1000, "Initializing", "Setting up News Tree", "Abort");
  986.  
  987.         UpdateNewsTree ();
  988.         SortList (&groupList, 0);
  989.         return;
  990. }
  991.  
  992. /************************************************************************/
  993.  
  994. void    ParseConfig (void)
  995. {
  996.         char    buf[512], *ps;
  997.         FILE    *fp;
  998.         BOOL    uulibFlag = 0;
  999.  
  1000.         // FIXME - use uucp:src/lib/config.c routines (specifically GetConfig())
  1001.  
  1002.         userName[0] = mailEditor[0] = newsEditor[0] = '\0';
  1003.         GetVar ("USERNAME",   userName,   256, GVF_GLOBAL_ONLY);
  1004.         GetVar ("NEWSEDITOR", newsEditor, 256, GVF_GLOBAL_ONLY);
  1005.         GetVar ("MAILEDITOR", mailEditor, 256, GVF_GLOBAL_ONLY);
  1006.         GetVar ("SENDMAIL",   sendMail,   256, GVF_GLOBAL_ONLY);
  1007.         GetVar ("POSTNEWS",   postNews,   256, GVF_GLOBAL_ONLY);
  1008.         if (userName[0] && newsEditor[0] && mailEditor[0] && sendMail[0] && postNews[0]) return;
  1009.  
  1010.         fp = fopen("s:uuconfig", "r");
  1011.         if (!fp) {
  1012.                 fp = fopen("uulib:config", "r");
  1013.                 panic0(fp, "Can't open uulib:config");
  1014.                 uulibFlag = !0;
  1015.         }
  1016.         while (fgets(buf, 512, fp) && (!userName[0] || !newsEditor[0] || !mailEditor[0] || !sendMail[0] || !postNews[0])) {
  1017.                 buf[strlen(buf)-1] = '\0';
  1018.                 if (userName[0] == '\0' && !strnicmp(buf, "UserName", 8)) {
  1019.                         ps = &buf[8];
  1020.                         while (*ps == ' ' || *ps == '\t') ps++;
  1021.                         if (*ps == '\0') panic("s:uuconfig or uulib:config UserName is NULL");
  1022.                         strcpy(userName, ps);
  1023.                 }
  1024.                 else if (newsEditor[0] == '\0' && !strnicmp(buf, "NewsEditor", 10)) {
  1025.                         ps = &buf[10];
  1026.                         while (*ps == ' ' || *ps == '\t') ps++;
  1027.                         if (*ps == '\0') panic("s:uuconfig or uulib:config NewsEditor is NULL");
  1028.                         strcpy(newsEditor, ps);
  1029.                 }
  1030.                 else if (mailEditor[0] == '\0' && !strnicmp(buf, "MailEditor", 10)) {
  1031.                         ps = &buf[10];
  1032.                         while (*ps == ' ' || *ps == '\t') ps++;
  1033.                         if (*ps == '\0') panic("s:uuconfig or uulib:config MailEditor is NULL");
  1034.                         strcpy(mailEditor, ps);
  1035.                 }
  1036.                 else if (sendMail[0] == '\0' && !strnicmp(buf, "SendMail", 8)) {
  1037.                         ps = &buf[8];
  1038.                         while (*ps == ' ' || *ps == '\t') ps++;
  1039.                         if (*ps == '\0') panic("s:uuconfig or uulib:config Sendmail is NULL");
  1040.                         strcpy(sendMail, ps);
  1041.                 }
  1042.                 else if (postNews[0] == '\0' && !strnicmp(buf, "PostNews", 8)) {
  1043.                         ps = &buf[8];
  1044.                         while (*ps == ' ' || *ps == '\t') ps++;
  1045.                         if (*ps == '\0') panic("s:uuconfig or uulib:config Postnews is NULL");
  1046.                         strcpy(postNews, ps);
  1047.                 }
  1048.                 else if (!strnicmp(buf, "UUNews", 6)) {
  1049.                         ps = &buf[6];
  1050.                         while (*ps == ' ' || *ps == '\t') ps++;
  1051.                         if (*ps) strcpy(uunews, ps);
  1052.                 }
  1053.                 else if (!uulibFlag && !strnicmp(buf, "UUlib", 5)) {
  1054.                         ps = &buf[5];
  1055.                         while (*ps == ' ' || *ps == '\t') ps++;
  1056.                         if (*ps) strcpy(uulib, ps);
  1057.                 }
  1058.                 else if (!strnicmp(buf, "UUSpool", 7)) {
  1059.                         ps = &buf[7];
  1060.                         while (*ps == ' ' || *ps == '\t') ps++;
  1061.                         if (*ps) strcpy(uuspool, ps);
  1062.                 }
  1063.         }
  1064.         fclose(fp);
  1065.         if (userName[0]) {
  1066.                 strcpy(grnrcName, uulib);
  1067.                 sprintf(buf, "%s.grnrc", userName);
  1068.                 AddPart(grnrcName, buf, 256);
  1069.         }
  1070.         else
  1071.                 panic("s:uuconfig or uulib:config must contain UserName!");
  1072.         if (newsEditor[0] && !mailEditor[0])
  1073.                 strcpy(mailEditor, newsEditor);
  1074.         else if (!newsEditor[0] && mailEditor[0])
  1075.                 strcpy(newsEditor, mailEditor);
  1076.         panic0((APTR)newsEditor[0], "s:uuconfig or uulib:config must contain NewsEditor");
  1077.         panic0((APTR)mailEditor[0], "s:uuconfig or uulib:config must contain MailEditor");
  1078.         if (!sendMail[0]) strcpy(sendMail, "SendMail");
  1079.         if (!postNews[0]) strcpy(postNews, "PostNews");
  1080.         if (!logfile[0]) {
  1081.                 strcpy(logfile, uuspool);
  1082.                 AddPart(logfile, "logfile", 256);
  1083.         }
  1084. }
  1085.  
  1086. /************************************************************************/
  1087.  
  1088. void    GRnRC (void)
  1089. {
  1090.         ULONG   testver = 0x0a0a5050;
  1091.  
  1092.         ParseConfig ();
  1093.         SetHierarchical ();
  1094.  
  1095.         if (!mopen (grnrcName)) {
  1096.                 BuildNewsTree ();
  1097.                 Abort ();
  1098.         }
  1099.         mread (&testver, 4);
  1100.         if (testver != grnrcVersion)
  1101.                 panic ("grnrc is wrong version, delete it and run GRn again");
  1102.  
  1103.         currentGroup = (GLIST *) groupList.lh_Head;
  1104.         ReadNewsTree ();
  1105.         UpdateNewsTree ();
  1106.         SortList (&groupList, 0);
  1107.         WriteNewsTree ();
  1108.         Abort ();
  1109.         /* NOTREACHED */
  1110.         return;
  1111. }
  1112.  
  1113. /************************************************************************/
  1114.  
  1115. void    QueryAbort (void)
  1116. {
  1117.         if (!treeDirty)
  1118.                 Abort ();
  1119.         if (TwoGadgetRequest ("GRn - Abort...",
  1120.                               "Quit without updating News Tree?",
  1121.                               "_YES",
  1122.                               "_NO, I changed my mind"))
  1123.                 Abort ();
  1124.         mode = GROUPS_MODE;
  1125.         return;
  1126. }
  1127.  
  1128. void    TRAP (void)
  1129. {
  1130.         UWORD   *custom = (UWORD *)0xdff180;
  1131.         UWORD   i = 0;
  1132.  
  1133.         while (1)
  1134.                 *custom = i++;
  1135. }
  1136.  
  1137. void usage (void)
  1138. {
  1139.         char *msg = "usage: grn [-u] [-s newsgrouplist]\n"
  1140.                     GRN_VERSION     "\n";
  1141.  
  1142.         write (2, msg, strlen (msg));
  1143.         exit (10);
  1144. }
  1145.  
  1146. int     main (int ac, char *av[])
  1147. {
  1148.         LIBRARY *check;
  1149.         STRPTR  s;
  1150.         char    **tt;
  1151.         BOOL    lFlag = 0, tFlag = 0, hFlag = 0;
  1152.  
  1153.         check = OpenLibrary ("intuition.library", 37);
  1154.         if (!check) {
  1155.                 printf ("Can't open intuition.library\n");
  1156.                 panic("Requires OS version 37 or higher");
  1157.         }
  1158.         CloseLibrary(check);
  1159.  
  1160.         if (ac > 1) {
  1161.                 // got arguments
  1162.                 // this is ugly, but for just a couple, why generalize?
  1163.                 if (strcmp (av [1], "-u") == 0) {
  1164.                         update_only_mode = 1;
  1165.                         if (ac > 2)
  1166.                                 usage ();
  1167.                 }
  1168.                 else
  1169.                         if (strcmp (av [1], "-s") == 0) {
  1170.                                 subscribe_mode = 1;
  1171.                                 subscribe_list = av;
  1172.                                 subscribe_count = ac - 2;
  1173.                         }
  1174.                         else {
  1175.                                 usage ();
  1176.                         }
  1177.         }
  1178.  
  1179.         if (ac == 0) {
  1180.                 WorkbenchBase = OpenLibrary("workbench.library", 0);
  1181.                 panic0(WorkbenchBase, "Can't open workbench.library");
  1182.                 IconBase = OpenLibrary("icon.library", 0);
  1183.                 panic0(IconBase, "Can't open icon.library");
  1184.                 CxBase = OpenLibrary("commodities.library", 0);
  1185.                 panic0(CxBase, "Can't open commodities.library");
  1186.                 tt = ArgArrayInit(ac, av);
  1187.                 panic0(tt, "Can't ArgArrayInit...");
  1188.  
  1189.                 s = ArgString(tt, "TOP", "");
  1190.                 if (s[0]) { prefTop = atoi(s); tFlag = !0; }
  1191.                 s = ArgString(tt, "LEFT", "");
  1192.                 if (s[0]) { prefLeft = atoi(s); lFlag = !0; }
  1193.                 s = ArgString(tt, "WIDTH", "");
  1194.                 if (s[0]) prefWidth = atoi(s);
  1195.                 s = ArgString(tt, "HEIGHT", "");
  1196.                 if (s[0]) { prefHeight = atoi(s); hFlag = !0; }
  1197.                 s = ArgString(tt, "MSGFONT", "");
  1198.                 if (s[0]) strcpy(prefFontName, s);
  1199.                 s = ArgString(tt, "MSGFONTSIZE", "");
  1200.                 if (s[0]) prefFontSize = atoi(s);
  1201.                 s = ArgString(tt, "LOGFILE", "");
  1202.                 if (s[0]) strcpy(logfile, s);
  1203.                 s = ArgString(tt, "WRAP", "");
  1204.                 if (s[0]) wrapCol = atoi(s);
  1205.                 s = ArgString(tt, "UPDATERC", "");
  1206.                 if (s[0]) update_only_mode = 1;
  1207.                 ArgArrayDone();
  1208.                 CloseLibrary(CxBase);
  1209.                 CloseLibrary(IconBase);
  1210.                 CloseLibrary(WorkbenchBase);
  1211.                 InitSystem ();
  1212.         }
  1213.         else {
  1214.                 InitSystem ();
  1215.                 prefLeft = screenWidth - prefWidth;
  1216.                 prefTop = screenTop;
  1217.                 prefHeight = screenHeight-screenTop;
  1218.         }
  1219.         if (ac == 0) {
  1220.                 if (!lFlag) prefLeft = screenWidth - prefWidth;
  1221.                 if (!tFlag) prefTop = screenTop;
  1222.                 if (!hFlag) prefHeight = screenHeight-screenTop;
  1223.         }
  1224.  
  1225.         onbreak(Abort);
  1226.  
  1227.         Forbid ();
  1228.         port = FindPort ("GRN_PORT");
  1229.         if (port) {
  1230.                 port = 0;
  1231.                 Permit ();
  1232.                 if (screen)
  1233.                         DisplayBeep (screen);
  1234.                 else
  1235.                         printf ("GRn already running!!!\n");
  1236.                 Abort();
  1237.         }
  1238.         port = CreatePort ("GRN_PORT", 0);
  1239.         Permit ();
  1240.         panic0 (port, "Can't create GRN_PORT");
  1241.  
  1242.         fib = (FIB *) AllocDosObject (DOS_FIB, TAG_DONE);
  1243.         panic0 (fib, "Can't AllocDosObject (DOS_FIB)");
  1244.  
  1245.         NewList (&groupList);
  1246.  
  1247.         if (update_only_mode) {
  1248.             GRnRC ();
  1249.             /* NOTREACHED */
  1250.             exit (0);
  1251.         }
  1252.         windowHeight = prefHeight;
  1253.         mainWindow = CreateWindow(NULL, prefLeft, prefTop, prefWidth,windowHeight, "GRn - Looking for news...");
  1254.         panic0(mainWindow, "Can't open main window");
  1255.  
  1256.         saveReq = (FILEREQ *)AllocAslRequestTags(ASL_FileRequest,
  1257.                 ASL_Hail, "Save Message...",
  1258.                 ASL_Window, mainWindow,
  1259.                 ASL_FuncFlags, FILF_SAVE,
  1260.                 TAG_DONE
  1261.         );
  1262.         panic0(saveReq, "Can't AllocFileRequest");
  1263.  
  1264.         publishReq = (FILEREQ *)AllocAslRequestTags(ASL_FileRequest,
  1265.                 ASL_Hail, "Publish File...",
  1266.                 ASL_Window, mainWindow,
  1267.                 TAG_DONE
  1268.         );
  1269.         panic0(publishReq, "Can't AllocFileRequest");
  1270.  
  1271.         t_printf(mainWindow, "GRn - Getting your UserName");
  1272.         ParseConfig();
  1273.         CheckNews();
  1274.  
  1275.         currentGroup = (GLIST *)groupList.lh_Head;
  1276.  
  1277.         while (mode != QUIT_MODE) {
  1278.                 switch (mode) {
  1279.                         case NEXTGROUPS_MODE:
  1280.                         case PREVGROUPS_MODE:
  1281.                         case GROUPS_MODE:       GroupsWindow(); break;
  1282.                         case ARTICLES_MODE:     ArticlesWindow(); break;
  1283.                         case QUIT_MODE:         break;
  1284.                         case ABORT_MODE:        QueryAbort(); break;
  1285.                         default:                break;
  1286.                 }
  1287.         }
  1288.         WriteNewsTree();
  1289.         Abort();
  1290. }
  1291.  
  1292. int     wbmain(struct WBStartup *msg) {
  1293.         LIBRARY *check;
  1294.         char    *s;
  1295.         BOOL    lFlag = 0, tFlag = 0, hFlag = 0;
  1296.         char    **tt;
  1297.         union {
  1298.                 char                    **args;
  1299.                 struct WBStartup        *msg;
  1300.         } argv;
  1301.  
  1302.         argv.msg = msg;
  1303.         check = OpenLibrary("intuition.library", 37);
  1304.         if (!check) panic("Requires OS version 37 or higher");
  1305.         CloseLibrary(check);
  1306.  
  1307.         WorkbenchBase = OpenLibrary("workbench.library", 0);
  1308.         panic0(WorkbenchBase, "Can't open workbench.library");
  1309.         IconBase = OpenLibrary("icon.library", 0);
  1310.         panic0(IconBase, "Can't open icon.library");
  1311.         CxBase = OpenLibrary("commodities.library", 0);
  1312.         panic0(CxBase, "Can't open commodities.library");
  1313.         CurrentDir(msg->sm_ArgList->wa_Lock); /* DICE's startup code doesn't do this */
  1314.         tt = ArgArrayInit(0, argv.args);
  1315.         panic0(tt, "Can't ArgArrayInit2...");
  1316.  
  1317.         s = ArgString(tt, "TOP", "");
  1318.         if (s[0]) { prefTop = atoi(s); tFlag = !0; }
  1319.         s = ArgString(tt, "LEFT", "");
  1320.         if (s[0]) { prefLeft = atoi(s); lFlag = !0; }
  1321.         s = ArgString(tt, "WIDTH", "");
  1322.         if (s[0]) prefWidth = atoi(s);
  1323.         s = ArgString(tt, "HEIGHT", "");
  1324.         if (s[0]) { prefHeight = atoi(s); hFlag = !0; }
  1325.         s = ArgString(tt, "MSGFONT", "");
  1326.         if (s[0]) strcpy(prefFontName, s);
  1327.         s = ArgString(tt, "MSGFONTSIZE", "");
  1328.         if (s[0]) prefFontSize = atoi(s);
  1329.         s = ArgString(tt, "LOGFILE", "");
  1330.         if (s[0]) strcpy(logfile, s);
  1331.         s = ArgString(tt, "WRAP", "");
  1332.         if (s[0]) wrapCol = atoi(s);
  1333.         s = ArgString(tt, "UPDATERC", "");
  1334.         if (s[0]) update_only_mode = 1;
  1335.         ArgArrayDone();
  1336.         CloseLibrary(CxBase);
  1337.         CloseLibrary(IconBase);
  1338.         CloseLibrary(WorkbenchBase);
  1339.         if (!lFlag) prefLeft = screenWidth - prefWidth;
  1340.         if (!tFlag) prefTop = screenTop;
  1341.         if (!hFlag) prefHeight = screenHeight-screenTop;
  1342.         return main(1,NULL);
  1343. }
  1344.  
  1345.