home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / comms / network / grn1asrc.lha / amode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-12  |  28.9 KB  |  1,113 lines

  1. #include    "defs.h"
  2.  
  3. extern char *FileNameToNewsGroup (char *filename);
  4. extern char *NewsGroupToFileName (char *newsgroup);
  5.  
  6. static LIST    msgList;
  7.  
  8. ART        *currentArticle;
  9.  
  10. /************************************************************************/
  11.  
  12. /*
  13.  * As each gadget in the GadDefs array above is created, it is assigned a UserID
  14.  * field value, incremented from zero.    The following defines are useful for switch
  15.  * statements, etc.  Enum would also work.  Be careful, if you add new gadgets in
  16.  * the middle of the initializations above, because you will need to renumber these
  17.  * defines.
  18.  */
  19. static enum GADGET_IDS {
  20.     ARTLIST_ID,
  21.     HIDEHEADERS_ID,
  22.     HIDEREAD_ID,
  23.     SORT_ID,
  24.     QUIT_ID,
  25.     PREV_ID,
  26.     NEXT_ID,
  27.     NEXTUNREAD_ID,
  28.     NEXTTHREAD_ID,
  29.     CATCHUP_ID,
  30.     PREVGROUP_ID,
  31.     NEXTGROUP_ID,
  32.     FROM_ID,
  33.     ORGANIZATION_ID,
  34.     DATE_ID,
  35.     SUBJECT_ID,
  36.     MSGLIST_ID,
  37.     STATUS_ID,
  38.     SAVE_ID,
  39.     REPLY_ID,
  40.     FORWARD_ID,
  41.     FOLLOWUP_ID,
  42.     POST_ID,
  43.     PRINT_ID,
  44.     MAXGADGET,
  45. };
  46.  
  47. static GADGET    *gadgetArray[MAXGADGET];
  48.  
  49. static char    *sortLabels[] = { "Number", "From", "Subject", 0 };
  50.  
  51. static short    viewHeight;        // height of MSGLIST listview in character lines
  52. static short    viewTop = 0;        // top line of MSGLIST view (for GTLV_Top pagedown
  53. static short    messageLines = 0;    // number of lines in message
  54.  
  55. /*
  56.  * Misc tags arrays
  57.  */
  58. static TAGS    nullTags[] = { GT_Underscore, '_', TAG_DONE,0 };
  59. static TAGS    disableTags[] = { GT_Underscore, '_', GA_Disabled,TRUE, TAG_DONE,0 };
  60. static TAGS    enableTags[] = { GT_Underscore, '_', GA_Disabled,FALSE, TAG_DONE,0 };
  61.  
  62. static TAGS    sortTags[] = {
  63.     GT_Underscore, '_',
  64.     GTCY_Labels, &sortLabels[0],
  65.     GTCY_Active, 0,
  66.     TAG_DONE, 0,
  67. };
  68.  
  69. static TAGS    artListTags[] = {
  70.     GT_Underscore, '_',
  71.     GTLV_Top, 0,
  72.     GTLV_Labels, 0,
  73.     GTLV_ReadOnly, FALSE,
  74.     GTLV_ScrollWidth, 16,
  75. #ifdef MYKE_REMOVED_THIS
  76.     GTLV_ShowSelected, NULL,
  77. #endif
  78.     GTBB_Recessed, FALSE,
  79.     TAG_DONE, 0,
  80. };
  81.  
  82. static TAGS    msgListTags[] = {
  83.     GT_Underscore, '_',
  84.     GTLV_Top, 0,
  85.     GTLV_Labels, &msgList,
  86.     GTLV_ReadOnly, TRUE,
  87.     GTLV_ScrollWidth, 16,
  88.     GTBB_Recessed, TRUE,
  89.     TAG_DONE, 0,
  90. };
  91.  
  92. static char    *nullText = "";
  93. static TAGS    textTags[] = {
  94.     GT_Underscore, '_',
  95.     GTTX_Text, (ULONG)"",
  96.     GTTX_CopyText, TRUE,
  97.     GTTX_Border, TRUE,
  98.     TAG_DONE, 0,
  99. };
  100.  
  101. /*
  102.  * The Array of Gadget definitions.  To create a new gadget, add an initializer
  103.  * here, and create the necessary tags...
  104.  */
  105. static GADDEF    gadDefs[] = {
  106.     artListTags, LISTVIEW_KIND,0,0,0,0, NG_HIGHLABEL, "",
  107.     nullTags, CHECKBOX_KIND, 0,0,0,0, NG_HIGHLABEL, "Hide Headers:",
  108.     disableTags, CHECKBOX_KIND, 0,0,0,0, NG_HIGHLABEL, "Hide Read Messages:",
  109.     sortTags, CYCLE_KIND, 0,0,0,0, NG_HIGHLABEL, "Sort By:",
  110.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "_Groups",
  111.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "_prev",
  112.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "_next",
  113.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "_unread",
  114.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "_thread",
  115.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "_Catch up",
  116.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "_Prev Group",
  117.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "_Next Group",
  118.     textTags, TEXT_KIND, 0,0,0,0, NG_HIGHLABEL, "From:",
  119.     textTags, TEXT_KIND, 0,0,0,0, NG_HIGHLABEL, "Org:",
  120.     textTags, TEXT_KIND, 0,0,0,0, NG_HIGHLABEL, "Date:",
  121.     textTags, TEXT_KIND, 0,0,0,0, NG_HIGHLABEL, "Subj:",
  122.     msgListTags, LISTVIEW_KIND, 0,0,0,0, NG_HIGHLABEL, "",
  123.     textTags, TEXT_KIND, 0,0,0,0, NG_HIGHLABEL, "",
  124.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "_Save",
  125.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "_Reply",
  126.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "Forward",
  127.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "_FollowUp",
  128.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "Post",
  129.     enableTags, BUTTON_KIND, 0,0,0,0, NG_HIGHLABEL, "Print",
  130.     0,0,0,0,0,0,0,0,
  131. };
  132.  
  133. static GADGET    *gList = 0;
  134.  
  135. static void    LayoutGadgets(font,width,height,top)
  136. FONT        *font;
  137. short        width,height,top;
  138. {
  139.     short    i, x,y, fh, lh;
  140.     RPORT    rPort, *rp = &rPort;
  141.  
  142.     InitRastPort(rp);
  143.     SetFont(rp, font);
  144.     y = top+INTERHEIGHT/2;
  145.  
  146.     lh = (windowHeight/50);
  147.     if (lh > 10) lh = 10;
  148.     fh = rp->TxHeight+2;
  149.     gadDefs[ARTLIST_ID].left = INTERWIDTH;
  150.     gadDefs[ARTLIST_ID].top = y;
  151.     gadDefs[ARTLIST_ID].width = width-INTERWIDTH-INTERWIDTH;
  152.     gadDefs[ARTLIST_ID].height = lh*fh+INTERHEIGHT;
  153.     y += lh*fh+INTERHEIGHT+2;
  154.  
  155.     fh = topazRP->TxHeight+2;
  156.     x = INTERWIDTH;
  157.     gadDefs[HIDEHEADERS_ID].left = x + TextLen(topazRP, gadDefs[HIDEHEADERS_ID].text)+20;
  158.     gadDefs[HIDEHEADERS_ID].top = y;
  159.     gadDefs[HIDEHEADERS_ID].width = 12;
  160.     gadDefs[HIDEHEADERS_ID].height = fh+2;
  161.     x = gadDefs[HIDEHEADERS_ID].left + gadDefs[HIDEHEADERS_ID].width + INTERWIDTH;
  162.  
  163.     gadDefs[HIDEREAD_ID].left = x + TextLen(topazRP, gadDefs[HIDEREAD_ID].text)+20;
  164.     gadDefs[HIDEREAD_ID].top = y;
  165.     gadDefs[HIDEREAD_ID].width = 12;
  166.     gadDefs[HIDEREAD_ID].height = fh+2;
  167.     x = gadDefs[HIDEREAD_ID].left + gadDefs[HIDEREAD_ID].width + INTERWIDTH;
  168.  
  169.     gadDefs[SORT_ID].left = x + TextLen(topazRP, gadDefs[SORT_ID].text)+20;
  170.     gadDefs[SORT_ID].top = y;
  171.     gadDefs[SORT_ID].width = TextLen(topazRP, "Subject")+24;
  172.     gadDefs[SORT_ID].height = fh+2;
  173.     x = gadDefs[SORT_ID].left + gadDefs[SORT_ID].width + INTERWIDTH;
  174.  
  175.     y += fh+4;
  176.  
  177.     x = INTERWIDTH;
  178.     for (i=QUIT_ID; i<=NEXTGROUP_ID; i++) {
  179.         gadDefs[i].left = x;
  180.         gadDefs[i].top = y;
  181.         gadDefs[i].width = TextLen(topazRP, gadDefs[i].text)+4;
  182.         gadDefs[i].height = fh+4;
  183.         x += gadDefs[i].width + INTERWIDTH;
  184.     }
  185.  
  186.     y += fh+4+INTERHEIGHT;
  187.  
  188.     for (i=FROM_ID; i<=SUBJECT_ID; i++) {
  189.         gadDefs[i].left = INTERWIDTH+48;
  190.         gadDefs[i].top = y;
  191.         gadDefs[i].width = width - 48-INTERWIDTH-INTERWIDTH;
  192.         gadDefs[i].height = fh+2;
  193.         y += fh+INTERHEIGHT;
  194.     }
  195.  
  196.     fh = rp->TxHeight+2;
  197.     gadDefs[MSGLIST_ID].left = INTERWIDTH;
  198.     gadDefs[MSGLIST_ID].top = y;
  199.     gadDefs[MSGLIST_ID].width = width-INTERWIDTH-INTERWIDTH;
  200.     gadDefs[MSGLIST_ID].height = height-y-fh-fh-INTERHEIGHT-INTERHEIGHT;
  201.     y += gadDefs[MSGLIST_ID].height;
  202.  
  203.     fh = topazRP->TxHeight+2;
  204.     viewHeight = gadDefs[MSGLIST_ID].height/fh;
  205.     gadDefs[STATUS_ID].left = INTERWIDTH;
  206.     gadDefs[STATUS_ID].top = y;
  207.     gadDefs[STATUS_ID].width = width-INTERWIDTH-INTERWIDTH;
  208.     gadDefs[STATUS_ID].height = fh+2;
  209.     y += fh+4;
  210.  
  211.     x = INTERWIDTH;
  212.     for (i=SAVE_ID; i<=PRINT_ID; i++) {
  213.         gadDefs[i].left = x;
  214.         gadDefs[i].top = y;
  215.         gadDefs[i].width = TextLen(topazRP, gadDefs[i].text)+4;
  216.         gadDefs[i].height = fh+2;
  217.         x += gadDefs[i].width+INTERWIDTH;
  218.     }
  219.     y += fh+4;
  220. }
  221.  
  222. /************************************************************************/
  223.  
  224. void    CloseArticles() {
  225.     if (!gList) return;
  226.     if (RemoveGList(mainWindow, gList, -1) == -1) {
  227.         printf("RemoveGList() failed\n");
  228.         return;
  229.     }
  230.     FreeGadgets(gList);
  231.     gList = 0;
  232.     ClearWindow();
  233.     RefreshGList(mainWindow->FirstGadget, mainWindow, 0, -1);
  234.     GT_RefreshWindow(mainWindow, NULL);
  235. }
  236.  
  237. /************************************************************************/
  238.  
  239. GLIST    *NextGroup() {
  240.     GLIST    *gp = currentGroup;
  241.  
  242.     do {
  243.         if (groupList.lh_TailPred == (NODE *)gp)
  244.             gp = (GLIST *)groupList.lh_Head;
  245.         else
  246.             gp = (GLIST *)gp->node.ln_Succ;
  247.     } while (!gp->articles && gp != currentGroup);
  248.     return gp;
  249. }
  250.  
  251. GLIST    *PrevGroup() {
  252.     GLIST    *gp = currentGroup;
  253.  
  254.     do {
  255.         if (groupList.lh_Head == (NODE *)gp)
  256.             gp = (GLIST *)groupList.lh_TailPred;
  257.         else
  258.             gp = (GLIST *)gp->node.ln_Pred;
  259.     } while (!gp->articles && gp != currentGroup);
  260.     return gp;
  261. }
  262.  
  263. void    SortArticles() {
  264.     switch (currentGroup->sortActive) {
  265.         case 0: SortArticlesByNumber(¤tGroup->artList); break;
  266.         case 1: SortArticlesByFrom(¤tGroup->artList); break;
  267.         case 2: SortArticlesBySubject(¤tGroup->artList); break;
  268.     }
  269. }
  270.  
  271. void    Save(void) {
  272.     ART    *ap = currentArticle;
  273.     char    temp[256], work[256];
  274.     char    filename[256];
  275.     FILE    *fp, *outfp;
  276.     int    fd;
  277.     ULONG    size, count = 0, pct;
  278.  
  279.     if (!AslRequestTags(saveReq, TAG_DONE)) return;
  280.     strcpy(filename, saveReq->rf_Dir);
  281.     AddPart(filename, saveReq->rf_File, 256);
  282.  
  283.     strcpy(temp, uunews);
  284.     AddPart(temp, NewsGroupToFileName (currentGroup->groupName), 256);
  285.     sprintf(work, "%d", ap->filenum);
  286.     AddPart(temp, work, 256);
  287.  
  288.     fd = open(temp, O_READ);
  289.     if (fd == -1) return;
  290.     size = lseek(fd, 0, 2); lseek(fd, 0, 0);
  291.     close(fd);
  292.     fp = fopen(temp, "r");
  293.     if (!fp) return;
  294.     outfp = fopen(filename, "w");
  295.     if (!outfp) { fclose(fp); return; }
  296.     while (fgets(temp, 256, fp)) {
  297.         count += strlen(temp);
  298.         pct = 100*count/size;
  299.         if (GuageRequest(pct,"GRn - Please Wait...", "       Saving        ", "Abort")) break;
  300.         fprintf(outfp, "%s", temp);
  301.     }
  302.     GuageRequest(1000,"GRn - Please Wait...", "       Saving       ", "Abort");
  303.     fclose(outfp); fclose(fp);
  304. }
  305.  
  306. void    Print(void) {
  307.     ART    *ap = currentArticle;
  308.     char    temp[256], work[256];
  309.     FILE    *fp, *outfp;
  310.     int    fd;
  311.     ULONG    size, count = 0, pct;
  312.  
  313.     strcpy(temp, uunews);
  314.     AddPart(temp, NewsGroupToFileName (currentGroup->groupName), 256);
  315.     sprintf(work, "%d", ap->filenum);
  316.     AddPart(temp, work, 256);
  317.  
  318.     fd = open(temp, O_READ);
  319.     if (fd == -1) return;
  320.     size = lseek(fd, 0, 2); lseek(fd, 0, 0);
  321.     close(fd);
  322.     fp = fopen(temp, "r");
  323.     if (!fp) return;
  324.     outfp = fopen("prt:", "w");
  325.     if (!outfp) { fclose(fp); return; }
  326.     while (fgets(temp, 256, fp)) {
  327.         count += strlen(temp);
  328.         pct = 100*count/size;
  329.         if (GuageRequest(pct,"GRn - Please Wait...", "      Printing      ", "Abort")) break;
  330.         fprintf(outfp, temp);
  331.     }
  332.     GuageRequest(1000,"GRn - Please Wait...", "      Printing      ", "Abort");
  333.     fprintf(outfp, "%c", 12);
  334.     fclose(outfp); fclose(fp);
  335. }
  336.  
  337. void    ExpandTabs(char *buf) {
  338.     short    col = 0;
  339.     static char work [512]; /* static for efficiency on entry */
  340.     char    *pd = &work[0], *ps = buf;
  341.  
  342.     while (1) {
  343.         switch (*ps) {
  344.             case '\t':      do {
  345.                         *pd++ = ' '; col++;
  346.                     } while ((col%8) && col < 510);
  347.                     ps++;
  348.                     if (col >= 510) {
  349.                         *pd++ = '\0';
  350.                         strcpy(buf, work);
  351.                         return;
  352.                     }
  353.                     break;
  354.             case '\0':      *pd++ = '\0';
  355.                     strcpy(buf, work);
  356.                     return;
  357.             default:    *pd++ = *ps++; col++; break;
  358.         }
  359.     }
  360. }
  361.  
  362. void    ShowMessage(ART *ap) {
  363.     FILE        *fp;
  364.     char        temp[512], work[512], *ps;
  365.     NODE        *np;
  366.     GLIST        *gp;
  367.     BOOL        headerDone = 0;
  368.     BOOL        flag = !0;
  369.     static char    artStatus[256], org[512], date[512];
  370.     short        len;
  371.     int        found_date;    /* found the Date: header */
  372.     int        found_org;    /* found the Organization: header */
  373.  
  374.     messageLines = 0;
  375.     if (currentArticle == ap) flag = 0;
  376.     currentArticle = ap;
  377.     GT_SetGadgetAttrs(gadgetArray[MSGLIST_ID], mainWindow, NULL, GTLV_Labels, ~0, TAG_DONE);
  378.     FreeListNodes(&msgList, TRUE);
  379.  
  380.     strcpy(temp, uunews);
  381.     AddPart(temp, NewsGroupToFileName (currentGroup->groupName), 512);
  382.     sprintf(work, "%d", ap->filenum);
  383.     AddPart(temp, work, 512);
  384.  
  385.     NewList(&msgList);
  386.     fp = fopen(temp, "r");
  387.     if (!fp) {
  388.         t_printf ("Couldn't open '%s' (group = '%s', number = %d)\n",
  389.             temp, currentGroup->groupName, ap->filenum);
  390.         return;
  391.     }
  392.     org[0] = '\0';
  393.     found_date = found_org = 0;
  394.     while (fgets(temp, 512, fp)) {
  395.         temp[strlen(temp)-1] = '\0'; /* trim trailing newline */
  396.         ExpandTabs(temp);
  397.  
  398.         /* Note: Headers ARE case sensitive per RFC. */
  399.         if (!headerDone && (found_date == 0 || found_org == 0)) {
  400.             /* stop looking when the headers are gone */
  401.             if (!strncmp (temp, "Date: ", 6)) {
  402.                 strcpy(date, &temp [6]);
  403.                 found_date = 1;
  404.             }
  405.             else
  406.                 if (!strncmp (temp, "Organization: ", 14)) {
  407.                     strcpy (org, &temp [14]);
  408.                     found_org = 1;
  409.                 }
  410.         }
  411.         if (temp [0] == '\0') {
  412.             if (!headerDone && currentGroup->hideHeaders) {
  413.                 headerDone = !0; continue;
  414.             }
  415.             headerDone = !0;
  416.         }
  417.         if (currentGroup->hideHeaders && !headerDone && strncmp(temp, "X-NewsSoftware:", 15)) continue;
  418.         ps = &temp[0];
  419.         if (temp[0] == '\0') strcpy(temp, " ");
  420.         while (strlen(ps)) {
  421.             strncpy(work, ps, wrapCol);
  422.             work[wrapCol] = '\0';
  423.             len = strlen(work);
  424.             if (len == wrapCol && strlen(ps) > wrapCol)
  425.                 strcat(work, "\\");
  426.             //
  427.             // These malloc()'s KILL performance. There MUST
  428.             // be a better way.....
  429.             //
  430.             np = (NODE *) malloc (sizeof (NODE));
  431.             if (!np) {
  432.                 fclose(fp);
  433.                 return;
  434.             }
  435.             np->ln_Name = (char *) malloc (strlen (work) + 1);
  436.             if (!np->ln_Name) {
  437.                 fclose (fp);
  438.                 free (np);
  439.                 return;
  440.             }
  441.             strcpy(np->ln_Name, work);
  442.             AddTail(&msgList, np);
  443.             messageLines++;
  444.             ps = &ps[len];
  445.         }
  446.     }
  447.     fclose(fp);
  448.     if (ap->state == UNREAD) {
  449.         treeDirty = !0;
  450.         if (currentGroup->unread) currentGroup->unread--;
  451.     }
  452.     ap->state = READ;
  453.     sprintf(ap->node.ln_Name, "%s %6d %-32.32s %.64s",
  454.         ap->state?"  READ ":"UNREAD ",
  455.         ap->filenum,
  456.         ap->from,
  457.         ap->subject
  458.     );
  459.     GT_SetGadgetAttrs(gadgetArray[MSGLIST_ID], mainWindow, NULL, GTLV_Labels, &msgList, TAG_DONE);
  460.     if (flag) {
  461.         GT_SetGadgetAttrs(gadgetArray[MSGLIST_ID], mainWindow, NULL, GTLV_Top, 0, TAG_DONE);
  462.         viewTop = 0;
  463.     }
  464.     gp = NextGroup();
  465.     sprintf(artStatus, " *** Article %6d (%d remaining) Next Group is %s",
  466.         ap->filenum,
  467.         currentGroup->unread,
  468.         currentGroup != gp ? gp->groupName : "No More"
  469.     );
  470.     GT_SetGadgetAttrs(gadgetArray[STATUS_ID], mainWindow, NULL, GTTX_Text, artStatus, TAG_DONE);
  471.     GT_SetGadgetAttrs(gadgetArray[FROM_ID], mainWindow, NULL, GTTX_Text, ap->from, TAG_DONE);
  472.     GT_SetGadgetAttrs(gadgetArray[ORGANIZATION_ID], mainWindow, NULL, GTTX_Text, org, TAG_DONE);
  473.     GT_SetGadgetAttrs(gadgetArray[DATE_ID], mainWindow, NULL, GTTX_Text, date, TAG_DONE);
  474.     GT_SetGadgetAttrs(gadgetArray[SUBJECT_ID], mainWindow, NULL, GTTX_Text, ap->subject, TAG_DONE);
  475.     GT_SetGadgetAttrs(gadgetArray[ARTLIST_ID], mainWindow, NULL, GTLV_Top, ap->index, TAG_DONE);
  476.     GT_RefreshWindow(mainWindow, NULL);
  477.     return;
  478. }
  479.  
  480. void    NextArticle() {
  481.     if (currentGroup->artList.lh_TailPred == (NODE *)currentArticle) return;
  482.     ShowMessage((ART *)currentArticle->node.ln_Succ);
  483. }
  484.  
  485. void    PrevArticle() {
  486.     if (currentGroup->artList.lh_Head == (NODE *)currentArticle) return;
  487.     ShowMessage((ART *)currentArticle->node.ln_Pred);
  488. }
  489.  
  490. void    Post(BOOL followupFlag) {
  491.     char    fname[256], rname[256], from[512], subject[512], msgid[256], refs[512], groups[512], temp[512];
  492.     char    work[256];
  493.     FILE    *fp, *outfp, *reffp;
  494.  
  495.     if (followupFlag) {
  496.         strcpy(temp, uunews);
  497.         AddPart(temp, NewsGroupToFileName (currentGroup->groupName), 256);
  498.         sprintf(fname, "%d", currentArticle->filenum);
  499.         AddPart(temp, fname, 256);
  500.  
  501.         fp = fopen(temp, "r");
  502.         if (!fp) {
  503.             t_printf(mainWindow, "Can't open %s for input", temp);
  504.             return;
  505.         }
  506.         // parse header
  507.         from[0] = msgid[0] = refs[0] = 0;
  508.         while (fgets(temp, 512, fp)) {
  509.             temp[strlen(temp)-1] = '\0';
  510.             if (temp[0] == '\0') break;
  511.             if (!strncmp(temp, "From: ", 6))
  512.                 strcpy(from, &temp[6]);
  513.             else if (!strnicmp(temp, "Message-ID: ", 12)) {
  514.                 strcpy(msgid, &temp[12]);
  515.             }
  516.             else if (!strnicmp(temp, "References: ", 12)) {
  517.                 strcpy(refs, &temp[12]);
  518.             }
  519.             else if (!strnicmp(temp, "Newsgroups: ", 12)) {
  520.                 strcpy(groups, &temp[12]);
  521.             }
  522.             else if (!strnicmp(temp, "Subject: ", 9)) {
  523.                 strcpy(subject, &temp[9]);
  524.             }
  525.         }
  526.     }
  527.     sprintf(fname, "t:%s%x-text.txt", userName, FindTask(0));
  528.     unlink(fname);
  529.     outfp = fopen(fname, "w");
  530.     if (!outfp) {
  531.         t_printf(mainWindow, "Can't open %s for output", fname);
  532.         fclose(fp);
  533.         return;
  534.     }
  535.     if (followupFlag)
  536.         fprintf(outfp, "Newsgroups: %s\n", groups);
  537.     else
  538.         fprintf(outfp, "Newsgroups: %s\n", currentGroup->groupName);
  539.  
  540.     if (followupFlag) {
  541.         if (!strnicmp(subject, "re:", 3))
  542.             fprintf(outfp, "Subject: %s\n", subject);
  543.         else
  544.         fprintf(outfp, "Subject: Re: %s\n", subject);
  545.     }
  546.     else
  547.         fprintf(outfp, "Subject: \n");
  548.     fprintf(outfp, "Distribution: world\n\n");
  549.  
  550.     if (followupFlag) {
  551.         if (msgid[0])
  552.             fprintf(outfp, "In article %s ", msgid);
  553.         else
  554.             fprintf(outfp, "In article ??? ");
  555.         if (from[0])
  556.             fprintf(outfp, "%s writes:\n", from);
  557.         else
  558.             fprintf(outfp, "??? writes:\n");
  559.         while (fgets(temp, 512, fp)) {
  560.             fprintf(outfp, ">%s", temp);
  561.         }
  562.         fclose(fp);
  563.     }
  564.     fprintf(outfp, "\n--\n");
  565.  
  566.     strcpy(temp, uulib);
  567.     sprintf(work, "%s.signature", userName);
  568.     AddPart(temp, work, 256);
  569.     fp = fopen(temp, "r");
  570.     if (!fp) {
  571.         strcpy(temp, uunews);
  572.         AddPart(temp, NewsGroupToFileName (currentGroup->groupName), 256);
  573.         AddPart(temp, work, 256);
  574.         fp = fopen(temp, "r");
  575.     }
  576.     if (!fp) {
  577.         strcpy(temp, uulib);
  578.         AddPart(temp, ".signature", 256);
  579.         fp = fopen(temp, "r");
  580.     }
  581.     if (!fp) {
  582.         fprintf(outfp, ".signature under construction\n");
  583.     }
  584.     else {
  585.         while (fgets(temp, 512, fp)) {
  586.             fprintf(outfp, "%s", temp);
  587.         }
  588.         fclose(fp);
  589.     }
  590.     fclose(outfp);
  591.     sprintf(temp, "%s %s", newsEditor, fname);
  592.     Execute(temp, 0,0);
  593.     if (!SendItRequest()) return;
  594.     sprintf(rname, "t:%s%x-refs.txt", userName, FindTask(0));
  595.     unlink(rname);
  596.     outfp = fopen(rname, "w");
  597.     if (followupFlag) {
  598.         if (refs[0] || msgid[0]) {
  599.             if (outfp) {
  600.                 fprintf(outfp, "References: ");
  601.                 if (refs[0]) fprintf(outfp, "%s ", refs);
  602.                 if (msgid[0]) fprintf(outfp, "%s", msgid);
  603.                 fprintf(outfp, "\n");
  604.             }
  605.         }
  606.     }
  607.  
  608.     // append user.nrefs to the refs file
  609.     if (outfp) {
  610.         strcpy(temp, uulib);
  611.         sprintf(work, "%s.nrefs", userName);
  612.         AddPart(temp, work, 256);
  613.         reffp = fopen(temp, "r");
  614.         if (reffp) {
  615.             while (fgets(temp, 512, reffp)) fprintf(outfp, "%s", temp);
  616.             fclose(reffp);
  617.         }
  618.     }
  619.     if (outfp) fprintf(outfp, "X-NewsSoftware: %s\n", GRN_VERSION);
  620.     if (outfp) {
  621.         fclose(outfp);
  622.         sprintf(temp, "RUN <nil: >nil: %s %s -R %s -x %s -x %s",
  623.             postNews, fname, rname, fname, rname
  624.         );
  625.  
  626.  
  627.     }
  628.     else {
  629.         sprintf(temp, "RUN <nil: >nil: %s %s -x %s",
  630.             postNews, fname, fname
  631.         );
  632.     }
  633.     Execute(temp, 0,0);
  634.     GT_RefreshWindow(mainWindow, NULL);
  635. }
  636.  
  637. void    Mail(BOOL replyFlag) {
  638.     char    fname[256], from[512], subject[512], msgid[256], temp[512], work[256];
  639.     FILE    *fp, *outfp;
  640.  
  641.     strcpy(temp, uunews);
  642.     AddPart(temp, NewsGroupToFileName (currentGroup->groupName), 256);
  643.     sprintf(fname, "%d", currentArticle->filenum);
  644.     AddPart(temp, fname, 256);
  645.  
  646.     fp = fopen(temp, "r");
  647.     if (!fp) {
  648.         t_printf(mainWindow, "Can't open %s for input", temp);
  649.         return;
  650.     }
  651.     // parse header
  652.     from[0] = msgid[0] = 0;
  653.     while (fgets(temp, 512, fp)) {
  654.         temp[strlen(temp)-1] = '\0';
  655.         if (temp[0] == '\0') break;
  656.         if (!strncmp(temp, "From: ", 6) && from[0] == '\0') {
  657.             strcpy(from, &temp[6]);
  658.         }
  659.         else if (!strncmp(temp, "Reply-To: ", 10)) {
  660.             strcpy(from, &temp[10]);
  661.         }
  662.         else if (!strncmp(temp, "Message-ID: ", 12)) {
  663.             strcpy(msgid, &temp[12]);
  664.         }
  665.         else if (!strncmp(temp, "Subject: ", 9)) {
  666.             strcpy(subject, &temp[9]);
  667.         }
  668.     }
  669.     sprintf(fname, "t:%s%x-text.txt", userName, FindTask(0));
  670.     unlink(fname);
  671.     outfp = fopen(fname, "w");
  672.     if (!outfp) {
  673.         t_printf(mainWindow, "Can't open %s for output", fname);
  674.         fclose(fp);
  675.         return;
  676.     }
  677.     if (from[0] && replyFlag)
  678.         fprintf(outfp, "To: %s\n", from);
  679.     else
  680.         fprintf(outfp, "To: \n");
  681.  
  682.     if (!subject[0])
  683.         fprintf(outfp, "Subject: NO SUBJECT\n");
  684.     else if (!strnicmp(subject, "re:", 3))
  685.         fprintf(outfp, "Subject: FYI: %s\n", subject);
  686.     else
  687.         fprintf(outfp, "Subject: FYI: %s\n", subject);
  688.  
  689.     if (msgid[0])
  690.         fprintf(outfp, "References: %s\n", msgid);
  691.  
  692.     fprintf(outfp, "X-NewsSoftware: %s\n\n", GRN_VERSION);
  693.  
  694.     if (msgid[0])
  695.         fprintf(outfp, "In article %s ", msgid);
  696.     else
  697.         fprintf(outfp, "In article ??? ");
  698.     if (replyFlag)
  699.         fprintf(outfp, "you wrote:\n");
  700.     else if (from[0])
  701.         fprintf(outfp, "%s writes:\n", from);
  702.     else
  703.         fprintf(outfp, "??? writes:\n");
  704.     while (fgets(temp, 512, fp)) {
  705.         fprintf(outfp, ">%s", temp);
  706.     }
  707.     fclose(fp);
  708.     fprintf(outfp, "\n--\n");
  709.  
  710.     strcpy(temp, uulib);
  711.     sprintf(work, "%s.signature", userName);
  712.     AddPart(temp, work, 256);
  713.     fp = fopen(temp, "r");
  714.     if (!fp) {
  715.         strcpy(temp, uulib);
  716.         AddPart(temp, ".signature", 256);
  717.         fp = fopen(temp, "r");
  718.     }
  719.     if (!fp) {
  720.         fprintf(outfp, ".signature under construction\n");
  721.     }
  722.     else {
  723.         while (fgets(temp, 512, fp)) {
  724.             fprintf(outfp, "%s", temp);
  725.         }
  726.         fclose(fp);
  727.     }
  728.     fclose(outfp);
  729.     sprintf(temp, "%s %s", mailEditor, fname);
  730.     Execute(temp, 0,0);
  731.     if (!TwoGadgetRequest("GRn - Request", "         Send it off?     ", "_YES", "_NO")) return;
  732.     sprintf(temp, "%s >nil: <%s -f %s",
  733.         sendMail, fname, userName
  734.     );
  735.     Execute(temp, 0,0);
  736.     unlink(fname);
  737. }
  738.  
  739. /************************************************************************/
  740.  
  741. BOOL    ParseThread(char *filename, char *refs, char *msgid) {
  742.     char    temp[512], *ps;
  743.     FILE    *fp;
  744.  
  745.     fp = fopen(filename, "r");
  746.     if (!fp) return 0;
  747.     if (refs) *refs = 0;
  748.     if (msgid) *msgid = 0;
  749.     while (fgets(temp, 512, fp)) {
  750.         temp[strlen(temp)-1] = '\0';
  751.         if (!strlen(temp)) break;
  752.         if (!strnicmp(temp, "References:", 11)) {
  753.             ps = &temp[11];
  754.             while (*ps == ' ') ps++;
  755.             strcpy(refs, ps);
  756.         }
  757.         else if (!strnicmp(temp, "Message-ID:", 11)) {
  758.             ps = &temp[11];
  759.             while (*ps == ' ') ps++;
  760.             strcpy(msgid, ps);
  761.         }
  762.     }
  763.     fclose(fp);
  764.     return !0;
  765. }
  766.  
  767. char    *ArticleName(ART *ap) {
  768.     static char    temp1[256], temp2[256];
  769.  
  770.     strcpy(temp1, uunews);
  771.     AddPart(temp1, NewsGroupToFileName (currentGroup->groupName), 256);
  772.     sprintf(temp2, "%d", ap->filenum);
  773.     AddPart(temp1, temp2, 256);
  774.     return &temp1[0];
  775. }
  776.  
  777. BOOL    RefCmp(char *ref1, char *ref2) {
  778.     char    r1[256], r2[256], *pd, *ps;
  779.  
  780.     while (*ref1) {
  781.         // get a reference from ref1 into r1
  782.         pd = &r1[0];
  783.         while (*ref1 && *ref1 != '<') ref1++;
  784.         if (*ref1 == '\0') return 0;
  785.         while (*ref1 && *ref1 != '>') *pd++ = *ref1++;
  786.         if (*ref1 == '>') *pd++ = *ref1++;
  787.         *pd = '\0';
  788.         // now compare against all refs in ref2
  789.         ps = ref2;
  790.         while (*ref2) {
  791.             // get a reference from ref2 into r2
  792.             pd = &r2[0];
  793.             while (*ps && *ps != '<') ps++;
  794.             if (*ps == '\0') return 0;
  795.             while (*ps && *ps != '>') *pd++ = *ps++;
  796.             if (*ps == '>') *pd++ = *ps++;
  797.             *pd = '\0';
  798.             if (!stricmp(r1, r2)) return !0;
  799.         }
  800.     }
  801.     return 0;
  802. }
  803.  
  804. BOOL    NextThread() {
  805.     ART    *ap;
  806.     char    myrefs[512], myid[256], refs[512], msgid[256], subj[256], *ps;
  807.  
  808.     ps = currentArticle->subject;
  809.     while (*ps == ' ') ps++;
  810.     if (!strnicmp(ps, "re:", 3)) ps = &ps[3];
  811.     while (*ps == ' ') ps++;
  812.     strcpy(subj, ps);
  813.     if (!ParseThread(ArticleName(currentArticle), myrefs, myid)) return 0;
  814.     ap = currentArticle;
  815.     do {
  816.         if (currentGroup->artList.lh_TailPred == (NODE *)ap)
  817.             ap = (ART *)currentGroup->artList.lh_Head;
  818.         else
  819.             ap = (ART *)ap->node.ln_Succ;
  820.         if (ap->state == UNREAD) {
  821.             if (!ParseThread(ArticleName(ap), refs, msgid)) continue;
  822.             ps = ap->subject;
  823.             while (*ps == ' ') ps++;
  824.             if (!strnicmp(ps, "re:", 3)) ps = &ps[3];
  825.             while (*ps == ' ') ps++;
  826.             if (RefCmp(myid, refs) || RefCmp(myrefs, refs) || RefCmp(msgid, myrefs) || !stricmp(subj, ps)) {
  827.                 ShowMessage(ap);
  828.                 return !0;
  829.             }
  830.         }
  831.     } while (ap != currentArticle);
  832.     return 0;
  833. }
  834.  
  835. /************************************************************************/
  836.  
  837. /*
  838.  * void ProcessGadget(id, code);
  839.  * UWORD    id;        gadgetID of gadget to process
  840.  * UWORD    code;        IntuiMessage Code
  841.  *
  842.  * Synopsis:
  843.  *    Process IDCMP message for GadTools gadget.  Simply prints an appropriate string
  844.  *    into the event listview, unless it is palette related (handles palette appropriately).
  845.  */
  846. static void    ProcessGadget(UWORD id, UWORD code) {
  847. /*    GADGET    *gad = gadgetArray[id]; */
  848.     ART    *ap;
  849.     GLIST    *gp;
  850.  
  851.     switch (id) {
  852.         case HIDEHEADERS_ID:
  853.             currentGroup->hideHeaders = !currentGroup->hideHeaders;
  854.             treeDirty = !0;
  855.             GT_SetGadgetAttrs(gadgetArray[HIDEHEADERS_ID], mainWindow, NULL,
  856.                 GTCB_Checked, currentGroup->hideHeaders?TRUE:FALSE,
  857.                 TAG_DONE
  858.             );
  859.             ShowMessage(currentArticle);
  860.             break;
  861.         case HIDEREAD_ID:
  862.             currentGroup->hideRead = !currentGroup->hideRead;
  863.             treeDirty = !0;
  864.             GT_SetGadgetAttrs(gadgetArray[HIDEREAD_ID], mainWindow, NULL,
  865.                 GTCB_Checked, currentGroup->hideRead?TRUE:FALSE,
  866.                 TAG_DONE
  867.             );
  868.             break;
  869.         case NEXTGROUP_ID:
  870.             gp = NextGroup();
  871.             if (gp != currentGroup) {
  872.                 mode = NEXTGROUPS_MODE;
  873.                 currentGroup = gp;
  874.             }
  875.             break;
  876.         case PREVGROUP_ID:
  877.             gp = PrevGroup();
  878.             if (gp != currentGroup) {
  879.                 mode = PREVGROUPS_MODE;
  880.                 currentGroup = gp;
  881.             }
  882.             break;
  883.         case QUIT_ID:
  884.             mode = GROUPS_MODE;
  885.             break;
  886.         case SORT_ID:
  887.             currentGroup->sortActive = code;
  888.             treeDirty = !0;
  889.             GT_SetGadgetAttrs(gadgetArray[ARTLIST_ID], mainWindow, NULL, GTLV_Labels, ~0, TAG_DONE);
  890.             SortArticles();
  891.             GT_SetGadgetAttrs(gadgetArray[ARTLIST_ID], mainWindow, NULL, GTLV_Labels, ¤tGroup->artList, TAG_DONE);
  892.             ShowMessage(currentArticle);
  893.             break;
  894.         case ARTLIST_ID:
  895.             ap = (ART *)FindListItem(¤tGroup->artList, code);
  896.             if (!ap)
  897.                 printf("Error: Can't FindListItem(%d)\n", code);
  898.             else {
  899.                 ShowMessage(ap);
  900.             }
  901.             break;
  902.         case PREV_ID:
  903.             PrevArticle();
  904.             break;
  905.         case NEXT_ID:
  906.             NextArticle();
  907.             break;
  908.         case NEXTUNREAD_ID:
  909.             ap = currentArticle;
  910.             do {
  911.                 if (currentGroup->artList.lh_TailPred == (NODE *)ap)
  912.                     ap = (ART *)currentGroup->artList.lh_Head;
  913.                 else
  914.                     ap = (ART *)ap->node.ln_Succ;
  915.                 if (ap->state == UNREAD) {
  916.                     ShowMessage(ap);
  917.                     return;
  918.                 }
  919.             } while (ap != currentArticle);
  920.             break;
  921.         case NEXTTHREAD_ID:
  922.             if (!NextThread()) {
  923.                 ap = currentArticle;
  924.                 do {
  925.                     if (currentGroup->artList.lh_TailPred == (NODE *)ap)
  926.                         ap = (ART *)currentGroup->artList.lh_Head;
  927.                     else
  928.                         ap = (ART *)ap->node.ln_Succ;
  929.                     if (ap->state == UNREAD) {
  930.                         ShowMessage(ap);
  931.                         return;
  932.                     }
  933.                 } while (ap != currentArticle);
  934.             }
  935.             break;
  936.         case CATCHUP_ID:
  937.             Catchup();
  938.             mode = NEXTGROUPS_MODE;
  939.             break;
  940.         case REPLY_ID:
  941.             Mail(TRUE);
  942.             break;
  943.         case FOLLOWUP_ID:
  944.             Post(TRUE);
  945.             break;
  946.         case POST_ID:
  947.             Post(FALSE);
  948.             break;
  949.         case FORWARD_ID:
  950.             Mail(FALSE);
  951.             break;
  952.         case PRINT_ID:
  953.             Print();
  954.             break;
  955.         case SAVE_ID:
  956.             Save();
  957.             break;
  958.         default:
  959.             t_printf(mainWindow, "ProcessGadget - id = %d", id); break;
  960.     }
  961. }
  962.  
  963. static void    IDCMPFunc(IMSG *m) {
  964.     GLIST    *gp;
  965.     ART    *ap;
  966.  
  967.     switch (m->Class) {
  968.         case IDCMP_CLOSEWINDOW:
  969.             mode = ABORT_MODE;
  970.             break;
  971.         case IDCMP_VANILLAKEY:
  972.             switch (m->Code) {
  973.                 case 'F':       Post(TRUE); break;
  974.                 case 'R':       Mail(TRUE); break;
  975.                 case 'n':       NextArticle(); break;
  976.                 case 'p':       PrevArticle(); break;
  977.                 case 'C':       Catchup();
  978.                         mode = NEXTGROUPS_MODE;
  979.                         break;
  980.                 case 'N':       gp = NextGroup();
  981.                         if (gp == currentGroup) break;
  982.                         mode = NEXTGROUPS_MODE;
  983.                         currentGroup = gp;
  984.                         break;
  985.                 case 'b':
  986.                 case 'P':       gp = PrevGroup();
  987.                         if (gp == currentGroup) break;
  988.                         mode = PREVGROUPS_MODE;
  989.                         currentGroup = gp;
  990.                         break;
  991.                 case ' ':       viewTop += viewHeight-2;
  992.                         if (viewTop > messageLines-viewHeight)
  993.                             viewTop = messageLines-viewHeight;
  994.                         if (viewTop < 0) viewTop = 0;
  995.                         GT_SetGadgetAttrs(gadgetArray[MSGLIST_ID], mainWindow, NULL,
  996.                             GTLV_Top, viewTop, TAG_DONE);
  997.                         break;
  998.                 case 'G':       mode = GROUPS_MODE; break;
  999.                 case 'S':       Save(); break;
  1000.                 case 't':       if (!NextThread()) {
  1001.                             ap = currentArticle;
  1002.                             do {
  1003.                                 if (currentGroup->artList.lh_TailPred == (NODE *)ap)
  1004.                                     ap = (ART *)currentGroup->artList.lh_Head;
  1005.                                 else
  1006.                                     ap = (ART *)ap->node.ln_Succ;
  1007.                                 if (ap->state == UNREAD) {
  1008.                                     ShowMessage(ap);
  1009.                                     return;
  1010.                                 }
  1011.                             } while (ap != currentArticle);
  1012.                         }
  1013.                         break;
  1014.                 case 'u':       ap = currentArticle;
  1015.                         do {
  1016.                             if (currentGroup->artList.lh_TailPred == (NODE *)ap)
  1017.                                 ap = (ART *)currentGroup->artList.lh_Head;
  1018.                             else
  1019.                                 ap = (ART *)ap->node.ln_Succ;
  1020.                             if (ap->state == UNREAD) {
  1021.                                 ShowMessage(ap);
  1022.                                 return;
  1023.                             }
  1024.                         } while (ap != currentArticle);
  1025.                         break;
  1026.             }
  1027.             break;
  1028.         case IDCMP_RAWKEY:
  1029.             switch (m->Code) {
  1030.                 case 0x4c:    // up key
  1031.                         if (viewTop) viewTop--;
  1032.                         if (viewTop < 0) viewTop = 0;
  1033.                         GT_SetGadgetAttrs(gadgetArray[MSGLIST_ID], mainWindow, NULL,
  1034.                             GTLV_Top, viewTop, TAG_DONE);
  1035.                         break;
  1036.                 case 0x4d:    // down key
  1037.                         viewTop++;
  1038.                         if (viewTop > messageLines-viewHeight)
  1039.                             viewTop = messageLines-viewHeight;
  1040.                         if (viewTop < 0) viewTop = 0;
  1041.                         GT_SetGadgetAttrs(gadgetArray[MSGLIST_ID], mainWindow, NULL,
  1042.                             GTLV_Top, viewTop, TAG_DONE);
  1043.                         break;
  1044.             }
  1045.  
  1046.     }
  1047. }
  1048.  
  1049. void    ArticlesWindow() {
  1050.     ART    *ap;
  1051.     UWORD    n = 0;
  1052.  
  1053.     if (!currentGroup || currentGroup->articles == 0) {
  1054.         mode = GROUPS_MODE;
  1055.         return;
  1056.     }
  1057.     NewList(&msgList);
  1058.     LayoutGadgets(defaultFont, prefWidth,windowHeight, screenTop);
  1059.     gList = CreateGadgets(&gadgetArray[0], &gadDefs[0]);
  1060.     AddGList(mainWindow, gList, -1, -1, 0);
  1061.     RefreshGList(gList, mainWindow, 0, -1);
  1062.     GT_RefreshWindow(mainWindow, NULL);
  1063.  
  1064.     GT_SetGadgetAttrs(gadgetArray[ARTLIST_ID], mainWindow, NULL, GTLV_Labels, ~0, TAG_DONE);
  1065.     for (ap=(ART *)currentGroup->artList.lh_Head; ap->node.ln_Succ; ap = (ART *)ap->node.ln_Succ) {
  1066.         sprintf(ap->node.ln_Name, "%s %6d %-32.32s %s",
  1067.             ap->state?"  READ ":"UNREAD ",
  1068.             ap->filenum,
  1069.             ap->from,
  1070.             ap->subject
  1071.         );
  1072.     }
  1073.     SortArticles();
  1074.     GT_SetGadgetAttrs(gadgetArray[ARTLIST_ID], mainWindow, NULL, GTLV_Labels, ¤tGroup->artList, TAG_DONE);
  1075.     GT_SetGadgetAttrs(gadgetArray[SORT_ID], mainWindow, NULL, GTCY_Active, currentGroup->sortActive, TAG_DONE);
  1076.     if (currentGroup->unread == 0) {        // show last READ message
  1077.         for (ap=(ART *)currentGroup->artList.lh_Head; ap->node.ln_Succ; ap = (ART *)ap->node.ln_Succ) {
  1078.             n++;
  1079.         }
  1080.         ShowMessage((ART *)currentGroup->artList.lh_TailPred);
  1081.     }
  1082.     else {    // show first unread message
  1083.         for (ap=(ART *)currentGroup->artList.lh_Head; ap->node.ln_Succ; ap = (ART *)ap->node.ln_Succ) {
  1084.             if (ap->state == UNREAD) break;
  1085.             n++;
  1086.         }
  1087.         ShowMessage(ap);
  1088.     }
  1089. #ifdef MYKE_REMOVED_THIS
  1090.     GT_SetGadgetAttrs(gadgetArray[ARTLIST_ID], mainWindow, NULL,
  1091.         GTLV_Selected, n,
  1092.         GTLV_Top, n,
  1093.         TAG_DONE
  1094.     );
  1095. #endif
  1096.  
  1097.     t_printf(mainWindow, "GRn - %s", currentGroup->groupName);
  1098.     GT_SetGadgetAttrs(gadgetArray[HIDEHEADERS_ID], mainWindow, NULL,
  1099.         GTCB_Checked, currentGroup->hideHeaders?TRUE:FALSE,
  1100.         TAG_DONE
  1101.     );
  1102.     GT_SetGadgetAttrs(gadgetArray[HIDEREAD_ID], mainWindow, NULL,
  1103.         GTCB_Checked, currentGroup->hideRead?TRUE:FALSE,
  1104.         TAG_DONE
  1105.     );
  1106.     while (mode == ARTICLES_MODE) {
  1107.         WaitPort (mainWindow->UserPort);
  1108.         EventHandler(mainWindow, ProcessGadget, IDCMPFunc, NULL);
  1109.     }
  1110.     FreeListNodes(&msgList, TRUE);
  1111.     CloseArticles();
  1112. }
  1113.