home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 4 / CDPD_IV.bin / networking / uucp / amigauucpsrc / dnews / main.c < prev    next >
C/C++ Source or Header  |  1994-06-29  |  14KB  |  653 lines

  1.  
  2. /*
  3.  *  MAIN.C
  4.  */
  5.  
  6. #include "defs.h"
  7.  
  8. #define MSTLEN    64    /*  # of forward referenced articles    */
  9.  
  10. char    User[32];
  11. NGroup    *GBase;
  12. NGroup    *CurGroup;
  13. void    *GrpDisp;
  14. void    *HelpDisp;
  15. void    *DataDisp;
  16. void    *ScanDisp;    /*  subject scan display    */
  17. char    *GroupFile = "T:DNews_Groups";
  18. char    *HelpFile = "T:DNews_Help";
  19. char    TmpBuf[TMPBSIZE];
  20.  
  21. long    MStack[MSTLEN];
  22. short    Mi;
  23. short    Mx;
  24. short    ShowAllGroups = 0;
  25.  
  26. #ifndef LATTICE
  27. void *GfxBase;
  28. void *IntuitionBase;
  29. #endif
  30.  
  31. Prototype char *FileForArticle(NGroup *, int);
  32. Prototype void SetGroup(NGroup *);
  33. Prototype void SetCurNo(NGroup *, int);
  34. Prototype int NumUnreadArticles(NGroup *);
  35.  
  36. Local NGroup *FindGroupByIndex(int);
  37. Local int  HandleKey(int);
  38. Local void UpdateGroupList(char *);
  39. Local void CreateHelpFile();
  40.  
  41. Local char *TitleForArticle(NGroup *);
  42.  
  43. IDENT(".07");
  44.  
  45. int
  46. brk()
  47. {
  48.     return(0);
  49. }
  50.  
  51. void
  52. closlib()
  53. {
  54.     if (GfxBase) {
  55.     CloseLibrary(GfxBase);
  56.     GfxBase = NULL;
  57.     }
  58.     if (IntuitionBase) {
  59.     CloseLibrary(IntuitionBase);
  60.     IntuitionBase = NULL;
  61.     }
  62. }
  63.  
  64.  
  65. main(ac, av)
  66. char **av;
  67. {
  68.     onbreak(brk);
  69.     atexit(closlib);
  70.  
  71.     IntuitionBase = OpenLibrary("intuition.library", 0);
  72.     GfxBase = OpenLibrary("graphics.library", 0);
  73.     if (IntuitionBase == NULL || GfxBase == NULL) {
  74.     puts("unable to open libraries");
  75.     exit(20);
  76.     }
  77.  
  78.     FindUser(User, sizeof(User));   /*  who am I ?  */
  79.     LoadGroups(User);               /*  load newsrc for user    */
  80.     LoadKillFile(User);
  81.     if (GBase == NULL) {
  82.     CreateNewsrc(User);
  83.     LoadGroups(User);
  84.     if (GBase == NULL) {
  85.         printf("Unable to find any news!\n");
  86.         exit(1);
  87.     }
  88.     }
  89.  
  90.     LoadDisplayConfig();
  91.  
  92.     UpdateGroupList(GroupFile);
  93.     GrpDisp = OpenBrowseDisplay(GroupFile, "h-help", 0);
  94.     if (GrpDisp == NULL) {
  95.     puts("unable to open window");
  96.     exit(1);
  97.     }
  98.  
  99.     /*
  100.      *    Handle browse events
  101.      */
  102.  
  103.     {
  104.     void *disp;
  105.     int row;
  106.     int col;
  107.     NGroup *grp;
  108.  
  109.     while (WaitBrowseEvent(&disp, &row, &col)) {
  110.         if (disp == GrpDisp) {      /*  handle main group list  */
  111.         if (row == -1) {        /*  close window    */
  112.             if (col == -1)
  113.             break;
  114.             if (HandleKey(col) < 0)
  115.             break;
  116.             continue;
  117.         }
  118.         if (grp = FindGroupByIndex(row))
  119.             SetGroup(grp);
  120.         continue;
  121.         }
  122.         if (disp == HelpDisp) {
  123.         if (row == -1) {
  124.             if (col == -1 || HandleKey(col) < 0) {
  125.             CloseBrowseDisplay(HelpDisp);
  126.             HelpDisp = NULL;
  127.             }
  128.         }
  129.         continue;
  130.         }
  131.         if (disp == DataDisp) {
  132.         if (row == -1) {
  133.             if (col == -1 || HandleKey(col) < 0) {
  134.             CloseBrowseDisplay(DataDisp);
  135.             DataDisp = NULL;
  136.             SetGroup(NULL);
  137.             }
  138.             continue;
  139.         }
  140.         }
  141.     }
  142.     }
  143.  
  144.     if (GrpDisp)
  145.     CloseBrowseDisplay(GrpDisp);
  146.     if (HelpDisp)
  147.     CloseBrowseDisplay(HelpDisp);
  148.     if (DataDisp)
  149.     CloseBrowseDisplay(DataDisp);
  150.     if (ScanDisp)
  151.     CloseBrowseDisplay(ScanDisp);
  152.     SaveKillFile(User);
  153.     UnloadGroups(User);
  154.     SaveDisplayConfig();
  155.     remove(GroupFile);
  156.     return(0);
  157. }
  158.  
  159. static void
  160. UpdateGroupList(file)
  161. char *file;
  162. {
  163.     FILE *fi;
  164.     NGroup *grp;
  165.  
  166.     fi = fopen(file, "w");
  167.     if (fi == NULL)
  168.     return;
  169.  
  170.     for (grp = GBase; grp; grp = grp->Next) {
  171.     long unread;
  172.  
  173.     if (grp->Enabled == 0) {
  174.         grp->Unread = 0;
  175.         continue;
  176.     }
  177.     grp->Unread = NumUnreadArticles(grp);
  178.     if (grp->Unread > 0 || ShowAllGroups)
  179.         fprintf(fi, "%-3d %-20s\n", NumUnreadArticles(grp), grp->Name);
  180.     }
  181.     fclose(fi);
  182. }
  183.  
  184. static int
  185. HandleKey(key)
  186. {
  187.     NGroup *grp = CurGroup;
  188.     int n;
  189.     int r = 0;
  190.  
  191.     for (;;) {
  192.     if (key != 'm' && key != 'M') {
  193.         Mi = 0;
  194.         Mx = 0;
  195.     }
  196.  
  197.     switch(key) {
  198.     case 'A':
  199.         ShowAllGroups = ~ShowAllGroups;
  200.         SetGroup(NULL);
  201.         break;
  202.     case 'h':
  203.         if (HelpDisp == NULL) {
  204.         CreateHelpFile();
  205.         HelpDisp = OpenBrowseDisplay(HelpFile, "HELP", 2);
  206.         }
  207.         break;
  208.     case 'v':       /*  first unread article    */
  209.         if (grp) {
  210.         n = NextNotInRange(grp->RList, 0);
  211.         if (n >= grp->MaxNo + 1)
  212.             n = grp->MaxNo;
  213.         grp->CurNo = n - 1;
  214.         /* SetCurNo(grp, n - 1); */
  215.         key = 's';
  216.         continue;
  217.         }
  218.         break;
  219.     case 'M':       /*  next reference auto-rewind          */
  220.     case 'm':       /*  next reference                      */
  221.         /*
  222.          *    Find an article that references this one.
  223.          */
  224.         if (grp->CurNo < grp->MaxNo)
  225.         RangeAdd(&grp->RList, grp->CurNo, grp->CurNo);
  226.  
  227.         if (grp) {
  228.         char *ref;
  229.         short alloced = 0;
  230.  
  231.         if (Mi || Mx == 0) {
  232.             ref = NewsMessageIdOf(grp, grp->CurNo);
  233.         } else {
  234.             short i;
  235.             char *tmp;
  236.  
  237.             ref = NULL;
  238.             if (tmp = ReferenceLineOf(grp, grp->CurNo)) {
  239.             for (i = Mx; i > 0; --i) {
  240.                 ref = NextRef(&tmp);
  241.                 if (ref == NULL)
  242.                 break;
  243.             }
  244.             }
  245.             if (ref) {
  246.             ref = strdup(ref);
  247.             alloced = 1;
  248.             }
  249.         }
  250.         if (ref) {
  251.             for (n = NextNotInRange(grp->RList, grp->CurNo); n < grp->MaxNo; n = NextNotInRange(grp->RList, n)) {
  252.             if (FindArticleReferencing(grp, ref, n))
  253.                 break;
  254.             }
  255.             if (alloced)
  256.             free(ref);
  257.             if (n >= grp->MaxNo) {      /*  no more references  */
  258.             if (Mi) {               /*  try refs to previous articles on the same line */
  259.                 n = MStack[--Mi];
  260.                 grp->CurNo = n;
  261.                 /* SetCurNo(grp, n); */
  262.                 continue;        /*  w/ same key */
  263.             }
  264.             ++Mx;            /*  try References: fields of original    */
  265.             continue;        /*  w/ same key */
  266.             }
  267.             if (Mi != MSTLEN)
  268.             MStack[Mi++] = n;
  269.             SetCurNo(grp, n);
  270.         } else {
  271.             Mx = 0;
  272.             Mi = 0;
  273.             if (key == 'M') {
  274.             key = 'v';
  275.             continue;
  276.             }
  277.         }
  278.         }
  279.         break;
  280.     case 'g':
  281.         if (grp) {
  282.         FILE *fi;
  283.         long artno = -1;
  284.         if (fi = fopen("CON:0/0/200/50/Article?", "w+")) {
  285.             fprintf(fi, ": ");
  286.             fflush(fi);
  287.             if (fgets(TmpBuf, sizeof(TmpBuf), fi))
  288.             artno = atoi(TmpBuf);
  289.             fclose(fi);
  290.         }
  291.         if (artno < 0)
  292.             artno = 0;
  293.         if (artno > grp->MaxNo)
  294.             artno = grp->MaxNo;
  295.         SetCurNo(grp, artno);
  296.         RangeDel(&grp->RList, artno, artno);
  297.         }
  298.         break;
  299.     case 'n':       /*  mark and go to next article         */
  300.     case '.':
  301.     case '>':
  302.         if (grp->CurNo < grp->MaxNo)
  303.         RangeAdd(&grp->RList, grp->CurNo, grp->CurNo);
  304.     case 's':       /*  do not mark and go to next article  */
  305.         grp->CurNo = NextNotInRange(grp->RList, grp->CurNo);
  306.         /* SetCurNo(grp, NextNotInRange(grp->RList, grp->CurNo)); */
  307.         if (grp->CurNo >= grp->MaxNo + 1) {
  308.         grp->CurNo = grp->MaxNo;
  309.         } else {
  310.         /*
  311.          *  skip past killed or non-existant articles, marking them as
  312.          *  we go
  313.          */
  314.  
  315.         if (ArticleRefKilled(grp, grp->CurNo)) {
  316.             RangeAdd(&grp->RList, grp->CurNo, grp->CurNo);
  317.             key = 's';
  318.             continue;
  319.         }
  320.         }
  321.         SetCurNo(grp, grp->CurNo);
  322.         break;
  323.     case 'b':
  324.     case '<':
  325.         if (grp) {
  326.         if (grp->CurNo == grp->PrevNo[0]) {
  327.             movmem(grp->PrevNo + 1, grp->PrevNo, sizeof(grp->PrevNo) - sizeof(grp->PrevNo[0]));
  328.             grp->PrevNo[arysize(grp->PrevNo)-1] = 0;
  329.         }
  330.         if (grp->PrevNo[0]) {
  331.             SetCurNo(grp, -grp->PrevNo[0]);
  332.             /*
  333.              * movmem(grp->PrevNo + 1, grp->PrevNo, sizeof(grp->PrevNo) - sizeof(grp->PrevNo[0]));
  334.              * grp->PrevNo[arysize(grp->PrevNo)-1] = 0;
  335.              */
  336.         } else if (grp->CurNo > 1) {
  337.             SetCurNo(grp, -(grp->CurNo - 1));
  338.         }
  339.         if (grp->CurNo)
  340.             RangeDel(&grp->RList, grp->CurNo, grp->CurNo);
  341.         }
  342.         break;
  343.     case 'k'&0x1F:  /*  from user for 30 days   */
  344.         if (grp->CurNo < grp->MaxNo)
  345.         RangeAdd(&grp->RList, grp->CurNo, grp->CurNo);
  346.         if (grp) {
  347.         char *ref;
  348.         if (ref = FromLineOf(grp, grp->CurNo))
  349.             AddKillFile(ref, 30, 1);
  350.         }
  351.         key = 'n';
  352.         continue;
  353.     case 'k':       /*  kill followups to this article and go to next article */
  354.     case 'K':       /*  for next 30 days        */
  355.         {
  356.         short t = ((key == 'k') ? 0 : 30);
  357.  
  358.         if (grp->CurNo < grp->MaxNo)
  359.             RangeAdd(&grp->RList, grp->CurNo, grp->CurNo);
  360.         if (grp) {
  361.             char *ref;
  362.             if (ref = NewsMessageIdOf(grp, grp->CurNo))
  363.             AddKillFile(ref, t, 0);
  364.             if (ref = ReferenceLineOf(grp, grp->CurNo))
  365.             AddKillFile(ref, t, 0);
  366.             if (ref = SubjectOf(grp, grp->CurNo, 1))
  367.             AddKillFile(ref, t, 1);
  368.         }
  369.         }
  370.         key = 'n';
  371.         continue;
  372.     case 'U':       /*  unkill followups            */
  373.         if (grp) {
  374.         char *ref;
  375.         if (ref = NewsMessageIdOf(grp, grp->CurNo))
  376.             RemKillFile(ref);
  377.         if (ref = ReferenceLineOf(grp, grp->CurNo))
  378.             RemKillFile(ref);
  379.         }
  380.         break;
  381.     case CTRL('g'): /*  goto specific article and mark as unread    */
  382.         break;
  383.     case '=':       /*  bring up subject scan window                */
  384.         break;
  385.     case '/':       /*  search in article               */
  386.         break;
  387.     case CTRL('/'): /*  search in all remaining articles*/
  388.         break;
  389.     case 'a':
  390.     case 'w':       /*  write article to file   */
  391.         if (grp) {
  392.         char *fn;
  393.  
  394.         if (fn = GetFileName(0)) {
  395.             FILE *fi = fopen(FileForArticle(grp, grp->CurNo), "r");
  396.             FILE *fo = fopen(fn, ((key == 'a') ? "a" : "w"));
  397.             long n;
  398.  
  399.             if (fi && fo) {
  400.             while ((n = fread(TmpBuf, 1, sizeof(TmpBuf), fi)) > 0)
  401.                 fwrite(TmpBuf, 1, n, fo);
  402.             }
  403.             if (fi)
  404.             fclose(fi);
  405.             if (fo)
  406.             fclose(fo);
  407.         }
  408.         }
  409.         break;
  410.     case 'r':       /*  reply to sender         */
  411.     case 'R':       /*  w/ text of current art  */
  412.         if (grp)
  413.         ReplyArticle(key, grp);
  414.         break;
  415.     case 'f':       /*  followup to newsgroup   */
  416.     case 'F':       /*  w/ text of current art  */
  417.         if (grp)
  418.         FollowUpArticle(key, grp);
  419.         break;
  420.     case 'p':       /*  post article (asynch)   */
  421.         PostArticle(grp);       /*  grp can be NULL!    */
  422.         break;
  423.     case 'N':
  424.         {
  425.         if (grp)
  426.             grp = grp->Next;
  427.  
  428.         if (ShowAllGroups == 0) {
  429.             while (grp && NumUnreadArticles(grp) == 0)
  430.             grp = grp->Next;
  431.         }
  432.  
  433.         if (grp == NULL) {
  434.             grp = GBase;
  435.             if (ShowAllGroups == 0) {
  436.             while (grp && NumUnreadArticles(grp) == 0)
  437.                 grp = grp->Next;
  438.             }
  439.         }
  440.         if (grp == NULL)    /*  set to NULL?    */
  441.             grp = GBase;
  442.  
  443.         SetGroup(grp);
  444.         }
  445.         break;
  446.     case 'P':
  447.         {
  448.         if (grp)
  449.             grp = PrevGroup(grp);
  450.  
  451.         if (ShowAllGroups == 0) {
  452.             while (grp && NumUnreadArticles(grp) == 0)
  453.             grp = PrevGroup(grp);
  454.         }
  455.  
  456.         if (grp == NULL) {
  457.             grp = LastGroup();
  458.             if (ShowAllGroups == 0) {
  459.             while (grp && NumUnreadArticles(grp) == 0)
  460.                 grp = PrevGroup(grp);
  461.             }
  462.         }
  463.         if (grp == NULL)    /*  set to NULL?    */
  464.             grp = LastGroup();
  465.  
  466.         SetGroup(grp);
  467.         }
  468.         break;
  469.     case 'q':
  470.     case 0x1B:
  471.         r = -1;
  472.         break;
  473.     default:
  474.         break;
  475.     }
  476.     break;
  477.     }
  478.     if (DataDisp && grp && (grp->Flags & GROUPF_REDISPLAY)) {
  479.     grp->Flags &= ~GROUPF_REDISPLAY;
  480.     ChangeBrowseDisplay(DataDisp, FileForArticle(grp, grp->CurNo), TitleForArticle(grp));
  481.     }
  482.     return(r);
  483. }
  484.  
  485. static NGroup *
  486. FindGroupByIndex(i)
  487. {
  488.     NGroup *grp;
  489.  
  490.     for (grp = GBase; grp; grp = grp->Next) {
  491.     if (grp->Enabled == 0)
  492.         continue;
  493.     if (grp->Unread > 0 || ShowAllGroups) {
  494.         if (i == 0)
  495.         break;
  496.         --i;
  497.     }
  498.     }
  499.     return(grp);
  500. }
  501.  
  502.  
  503. char *
  504. FileForArticle(grp, artno)
  505. NGroup *grp;
  506. {
  507.     static char Buf[512];
  508.     char *path = HandleHeirarchy(GetConfigDir(UUNEWS), grp->Name, 1);
  509.  
  510.     if (path) {
  511.     sprintf(Buf, "%s/%d", path, artno);
  512.     free(path);
  513.     } else {
  514.     sprintf(Buf, "BAD/%d", path, artno);    /*  shouldn't happen */
  515.     }
  516.     return(Buf);
  517. }
  518.  
  519. void
  520. CreateHelpFile()
  521. {
  522.     FILE *fi;
  523.     if (fi = fopen(HelpFile, "w")) {
  524.     fputs(
  525.         "use mouse buttons to select newsgroup\n"
  526.         "\n"
  527.         "h   -help\n"
  528.         "v   -first unread article (usually after m's)\n"
  529.         "m   -mark article read and follow references, stop at end\n"
  530.         "M   -mark article read and follow references, 'v' at end\n"
  531.         "n   -mark article read and goto next\n"
  532.         "s   -do not mark and goto next unread\n"
  533.         "b   -backup to previously read article\n"
  534.         "k   -kill refs to article (this session only)\n"
  535.         "K   -kill refs to article for 30 days\n"
  536.         "^k  -kill refs from user for 30 days\n"
  537.         "U   -unkill refs to article by id / user\n"
  538.         "w   -overWrite article to file\n"
  539.         "a   -Append article to file\n"
  540.         "r   -reply to sender of article\n"
  541.         "R   -reply to sender, include article contents\n"
  542.         "f   -followup to newsgroup\n"
  543.         "F   -followup to newsgroup, include article contents\n"
  544.         "p   -post a new article\n"
  545.         "A   -toggle all-groups/groups-with-msgs\n"
  546.         "N   -NEXT GROUP\n"
  547.         "P   -PREV GROUP\n"
  548.         "q   -quit window\n"
  549.  
  550.         "4   -left half of article\n"
  551.         "6   -right half of article\n"
  552.         "8   -page up\n"
  553.         "2   -page down (SPACE also pages down)\n"
  554.         "3   -bottom of article\n"
  555.         "9   -top of article\n"
  556.  
  557.         "    -(space) page down\n"
  558.         "CR  -(return) two lines down\n"
  559.  
  560.         "\n", fi
  561.     );
  562.     fclose(fi);
  563.     }
  564. }
  565.  
  566. char *
  567. TitleForArticle(grp)
  568. NGroup *grp;
  569. {
  570.     char *fname = FileForArticle(grp, grp->CurNo);
  571.     char *ptr;
  572.  
  573.     ptr = fname + strlen(fname);
  574.  
  575.     while (ptr > fname && *ptr != '/')
  576.     --ptr;
  577.     --ptr;
  578.     while (ptr >= fname && *ptr != '/')
  579.     --ptr;
  580.     ++ptr;
  581.  
  582.     sprintf(TmpBuf, "%s (%d)", ptr, grp->MaxNo - 1);
  583.     return(TmpBuf);
  584. }
  585.  
  586.  
  587. void
  588. SetGroup(grp)
  589. NGroup *grp;
  590. {
  591.     if (CurGroup)
  592.     ClearGroupCache(CurGroup);
  593.     if (grp) {
  594.     CurGroup = grp;
  595.     Mi = 0;
  596.     Mx = 0;
  597.     if (DataDisp)
  598.         ChangeBrowseDisplay(DataDisp, FileForArticle(grp, grp->CurNo), TitleForArticle(grp));
  599.     else
  600.         DataDisp = OpenBrowseDisplay(FileForArticle(grp, grp->CurNo), TitleForArticle(grp), 1);
  601.     }
  602.     /*
  603.      *    ChangeBrowseDisplay() closes file so we can update it, only openning
  604.      *    it again when actually scanned on a display refresh.
  605.      */
  606.     ChangeBrowseDisplay(GrpDisp,GroupFile,"h-help");
  607.     UpdateGroupList(GroupFile);
  608.     RefreshBrowseDisplay(GrpDisp, 1);
  609. }
  610.  
  611. void
  612. SetCurNo(grp, n)
  613. NGroup *grp;
  614. int n;
  615. {
  616.     short addbkup = 1;
  617.     int oldno = grp->CurNo;
  618.  
  619.     if (n < 0) {
  620.     n = -n;
  621.     addbkup = 0;
  622.     }
  623.  
  624.     grp->Flags |= GROUPF_REDISPLAY;
  625.     grp->CurNo = n;
  626.  
  627.     if (addbkup && oldno && grp->PrevNo[0] != oldno) {
  628.     movmem(grp->PrevNo, grp->PrevNo + 1, sizeof(grp->PrevNo) - sizeof(grp->PrevNo[0]));
  629.     grp->PrevNo[0] = oldno;
  630.     }
  631. }
  632.  
  633. int
  634. NumUnreadArticles(grp)
  635. NGroup *grp;
  636. {
  637.     int n = grp->MaxNo - 1;    /*  number of articles starting at 1    */
  638.  
  639.     if (grp) {
  640.     Range *ran;
  641.  
  642.     for (ran = grp->RList; ran; ran = ran->Next) {
  643.         if (ran->SNo == 0)  /*  do not include 0   */
  644.         ++n;
  645.         n -= ran->ENo - ran->SNo + 1;
  646.     }
  647.     }
  648.     if (n < 0)
  649.     n = 0;
  650.     return(n);
  651. }
  652.  
  653.