home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume30 / tin / part09 / newsrc.c < prev    next >
C/C++ Source or Header  |  1992-05-20  |  20KB  |  1,030 lines

  1. /*
  2.  *  Project   : tin - a threaded Netnews reader
  3.  *  Module    : newsrc.c
  4.  *  Author    : I.Lea & R.Skrenta
  5.  *  Created   : 01-04-91
  6.  *  Updated   : 19-04-92
  7.  *  Notes     :
  8.  *  Copyright : (c) Copyright 1991-92 by Iain Lea & Rich Skrenta
  9.  *              You may  freely  copy or  redistribute  this software,
  10.  *              so  long as there is no profit made from its use, sale
  11.  *              trade or  reproduction.  You may not change this copy-
  12.  *              right notice, and it must be included in any copy made
  13.  */
  14.  
  15. #include    "tin.h"
  16.  
  17.  
  18. /*
  19.  * Automatically subscribe user to newsgroups specified in
  20.  * /usr/lib/news/subscribe (locally) or same file but from
  21.  * NNTP server (LIST AUTOSUBSCRIBE) and create .newsrc
  22.  */
  23.  
  24. int auto_subscribe_groups ()
  25. {
  26.     char buf[LEN];
  27.     FILE *fp_newsrc;
  28.     FILE *fp_subs;
  29.     int len;
  30.     int ret_code = FALSE;
  31.     
  32.     if ((fp_subs = open_subscription_fp ()) != NULL) {
  33.         if ((fp_newsrc = fopen (newsrc, "w")) != NULL) {
  34.             while (fgets (buf, sizeof (buf), fp_subs) != NULL) {
  35.                 len = strlen (buf);
  36.                 if (len > 1) {
  37.                     buf[len-1] = '\0';
  38.                     fprintf (fp_newsrc, "%s:\n", buf);
  39.                 }    
  40.             }    
  41.             fclose (fp_newsrc);
  42.             ret_code = TRUE;
  43.         }    
  44.         fclose (fp_subs);
  45.     }
  46.  
  47.     return (ret_code);
  48. }
  49.  
  50. /*
  51.  * make a backup of users .newsrc in case of the bogie man
  52.  */
  53.  
  54. void backup_newsrc ()
  55. {
  56.     char buf[8192];
  57.     FILE *fp_newsrc, *fp_backup;
  58.     
  59.     if ((fp_newsrc = fopen (newsrc, "r")) != NULL) {
  60.         sprintf (buf, "%s/.oldnewsrc", homedir);
  61.         unlink (buf);    /* because rn makes a link of .newsrc -> .oldnewsrc */
  62.         if ((fp_backup = fopen (buf, "w")) != NULL) {
  63.             while (fgets (buf, sizeof (buf), fp_newsrc) != NULL) {
  64.                 fputs (buf, fp_backup);
  65.             }
  66.             fclose (fp_backup);
  67.         }
  68.         fclose (fp_newsrc);
  69.     }
  70. }
  71.  
  72. /*
  73.  *  Read $HOME/.newsrc into my_group[]. my_group[] ints point to
  74.  *  active[] entries.  Sub_only determines  whether to just read
  75.  *  subscribed groups or all of them.
  76.  */
  77.  
  78. void read_newsrc (sub_only)
  79.     int sub_only;        /* TRUE=subscribed groups only, FALSE=all groups */
  80. {
  81.     char c, *p, buf[8192];
  82.     char old_groups[LEN];
  83.     FILE *fp = (FILE *) 0;
  84.     FILE *fp_old = (FILE *) 0;
  85.     int i;
  86.     int remove_old_groups = FALSE;
  87.  
  88.     group_top = 0;
  89.  
  90. reread_newsrc:
  91.  
  92.     if ((fp = fopen (newsrc, "r")) == NULL) {    /* attempt to make a .newsrc */
  93.         if (auto_subscribe_groups ()) {        /* attempt to auto create newsrc */
  94.             goto reread_newsrc;
  95.         }    
  96.         for (i = 0; i < num_active; i++) {
  97.             if (group_top >= max_active) {
  98.                 expand_active ();
  99.             }
  100.             my_group[group_top] = i;
  101.             active[i].flag = 0;
  102.             unread[group_top] = -1;
  103.             group_top++;
  104.         }
  105.         write_newsrc ();
  106.         return;
  107.     }
  108.  
  109.     sprintf (old_groups, "%s/.newsrc.%d", homedir, process_id);
  110.  
  111.     while (fgets (buf, sizeof buf, fp) != NULL) {
  112.         p = buf;
  113.         while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  114.             p++;
  115.         c = *p;
  116.         *p++ = '\0';
  117.  
  118.         if (c == '!' && sub_only)
  119.             continue;        /* unsubscribed */
  120.  
  121.         if ((i = add_group (buf, FALSE)) < 0) {
  122.             if (! remove_old_groups) {
  123.                 if ((fp_old = fopen (old_groups, "w")) == NULL) {
  124.                     perror_message (txt_cannot_open, old_groups);
  125.                     continue;
  126.                 }
  127.                 remove_old_groups = TRUE;
  128.             }
  129.             fprintf (fp_old, "%s\n", buf);
  130.             continue;
  131.         }
  132.  
  133.         if (c != '!')        /* if we're subscribed to it */
  134.             active[my_group[i]].flag |= SUBSCRIBED;
  135.  
  136.         unread[i] = parse_unread (p, my_group[i]);
  137.     }
  138.     fclose (fp);
  139.  
  140.     /*
  141.      *  rewrite newsrc to get rid of any non-existant groups 
  142.      */
  143.     if (remove_old_groups) {
  144.         fclose (fp_old);
  145.         rewrite_newsrc ();
  146.     }
  147. }
  148.  
  149. /*
  150.  *  Write a new newsrc from my_group[] and active[] mygroup if
  151.  *  rewriting to get rid of groups that don't exist any longer. Used
  152.  *  to a create a new .newsrc if there isn't one already, or when
  153.  *  the newsrc is reset.
  154.  */
  155.  
  156. void write_newsrc ()
  157. {
  158.     FILE *fp;
  159.     int i;
  160.  
  161.     if ((fp = fopen (newsrc, "w")) == NULL) {
  162.         return;
  163.     }
  164.  
  165.     wait_message (txt_creating_newsrc);
  166.  
  167.     for (i=0 ; i < num_active ; i++) {
  168.         fprintf (fp, "%s! \n", active[i].name);
  169.     }
  170.  
  171.     fclose (fp);
  172. }
  173.  
  174. /*
  175.  *  Rewrite newsrc to get rid of groups that don't exist any longer.
  176.  */
  177.  
  178. void rewrite_newsrc ()
  179. {
  180.     char buf[8192], old[LEN];
  181.     char old_groups[LEN];
  182.     FILE *fp, *fp_old, *fp_new;
  183.     int found_old_group, len;    
  184.  
  185.     sprintf (old_groups, "%s/.newsrc.%d", homedir, process_id);
  186.  
  187.     if ((fp = fopen (newsrc, "r")) == NULL)
  188.         goto removed_old_groups_done;
  189.  
  190.     if ((fp_old = fopen (old_groups, "r")) == NULL)
  191.         goto removed_old_groups_done;
  192.  
  193.     if ((fp_new = fopen (newnewsrc, "w")) == NULL)
  194.         goto removed_old_groups_done;
  195.  
  196.     while (fgets (buf, sizeof buf, fp) != NULL) {            /* read group from newsrc */
  197.         rewind (fp_old);
  198.         found_old_group = FALSE;    
  199.         while (fgets (old, sizeof old, fp_old) != NULL) {    /* read group from oldgroups */
  200.             len = strlen (old)-1;
  201.             if ((buf[len] == ':' || buf[len] == '!') &&
  202.                 strncmp (buf, old, len) == 0) {
  203.                 old[len] = '\0';
  204.                 sprintf (msg, txt_deleting_from_newsrc, old);
  205.                 wait_message (msg);
  206.                 if (cmd_line) {
  207.                     wait_message ("\n");
  208.                 }    
  209.                 found_old_group = TRUE;    
  210.             }
  211.         }
  212.         if (! found_old_group) {
  213.             fprintf (fp_new, "%s", buf);
  214.         }
  215.     }
  216.     
  217.     fclose (fp);
  218.     fclose (fp_old);
  219.     fclose (fp_new);
  220.  
  221.     rename_file (newnewsrc, newsrc);
  222.  
  223. removed_old_groups_done:
  224.     unlink (old_groups);
  225. }
  226.  
  227. /*
  228.  *  Load the sequencer rang lists and mark arts[] according to the
  229.  *  .newsrc info for a particular group.  i.e.  rec.arts.comics: 1-94,97
  230.  */
  231.  
  232. void read_newsrc_line (group)
  233.     char *group;
  234. {
  235.     FILE *fp;
  236.     char buf[8192];
  237.     char *p;
  238.  
  239.     if ((fp = fopen (newsrc, "r")) == NULL)
  240.         return;
  241.  
  242.     while (fgets (buf, sizeof buf, fp) != NULL) {
  243.         p = buf;
  244.         while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  245.             p++;
  246.         *p++ = '\0';
  247.         if (strcmp (buf, group) != 0)
  248.             continue;
  249.         parse_seq (p);
  250.         break;
  251.     }
  252.  
  253.     fclose (fp);
  254. }
  255.  
  256. /*
  257.  *  For our current group, update the sequencer information in .newsrc
  258.  */
  259.  
  260. void update_newsrc (group, groupnum, mark_unread)
  261.     char *group;
  262.     int groupnum;            /* index into active[] for this group */
  263.     int mark_unread;
  264. {
  265.     FILE *fp;
  266.     FILE *newfp;
  267.     char buf[8192];
  268.     char *p;
  269.     char c;
  270.  
  271.     if ((newfp = fopen (newnewsrc, "w")) == NULL) {
  272.         goto update_done;
  273.     }
  274.  
  275.     if ((fp = fopen (newsrc, "r")) != NULL) {
  276.         while (fgets (buf, sizeof buf, fp) != NULL) {
  277.             for (p = buf; *p; p++)
  278.                 if (*p == '\n') {
  279.                     *p = '\0';
  280.                     break;
  281.                 }
  282.  
  283.             p = buf;
  284.             while (*p && *p != ' ' && *p != ':' && *p != '!')
  285.                     p++;
  286.             c = *p;
  287.             if (c != '\0')
  288.                 *p++ = '\0';
  289.  
  290.             if (c != '!' && c != ' ')
  291.                 c = ':';
  292.  
  293.             if (strcmp (buf, group) == 0) {
  294.                 if (mark_unread) {
  295.                     fprintf (newfp, "%s%c\n", buf, c);
  296.                 } else {
  297.                     fprintf (newfp, "%s%c ", buf, c);
  298.                     print_seq (newfp, groupnum);
  299.                     fprintf (newfp, "\n");
  300.                 }
  301.             } else
  302.                 fprintf (newfp, "%s%c%s\n", buf, c, p);
  303.         }
  304.         fclose (fp);
  305.     }
  306.  
  307.     fclose (newfp);
  308.     rename_file (newnewsrc, newsrc);
  309.  
  310. update_done:
  311.     ;
  312. }
  313.  
  314. /*
  315.  *  Subscribe/unsubscribe to a group in .newsrc.  ch should either be
  316.  *  '!' to unsubscribe or ':' to subscribe.  num is the group's index
  317.  *  in active[].
  318.  */
  319.  
  320. void subscribe (group, ch, num, out_seq)
  321.     char *group;
  322.     char ch;
  323.     int num;
  324.     int out_seq;                /* output sequencer info? */
  325. {
  326.     FILE *fp;
  327.     FILE *newfp;
  328.     char buf[8192];
  329.     char *p;
  330.     char c;
  331.     int gotit = FALSE;
  332.  
  333.     if (ch == '!')
  334.         active[num].flag &= ~SUBSCRIBED;
  335.     else
  336.         active[num].flag |= SUBSCRIBED;
  337.  
  338.     if ((newfp = fopen (newnewsrc, "w")) == NULL)
  339.         goto subscribe_done;
  340.  
  341.     if ((fp = fopen (newsrc, "r")) != NULL) {
  342.         while (fgets (buf, sizeof buf, fp) != NULL) {
  343.             if (strncmp ("options ", buf, 8) == 0) {
  344.                 fprintf (newfp, buf);
  345.             } else {
  346.                 for (p = buf; *p; p++) {
  347.                     if (*p == '\n') {
  348.                         *p = '\0';
  349.                         break;
  350.                     }
  351.                 }    
  352.  
  353.                 p = buf;
  354.                 while (*p && *p != ' ' && *p != ':' && *p != '!')
  355.                         p++;
  356.                 c = *p;
  357.                 if (c != '\0')
  358.                     *p++ = '\0';
  359.  
  360.                 if (c != '!')
  361.                     c = ':';
  362.  
  363.                 if (strcmp (buf, group) == 0) {
  364.                     fprintf (newfp, "%s%c%s\n", buf, ch, p);
  365.                     gotit = TRUE;
  366.                 } else {
  367.                     fprintf (newfp, "%s%c%s\n", buf, c, p);
  368.                 }
  369.             }
  370.         }
  371.         fclose (fp);
  372.     }
  373.  
  374.     if (! gotit) {
  375.         if (out_seq) {
  376.             fprintf (newfp, "%s%c ", group, ch);
  377.             print_seq (newfp, num);
  378.             fprintf (newfp, "\n");
  379.         } else
  380.             fprintf (newfp, "%s%c\n", group, ch);
  381.     }
  382.  
  383.     fclose (newfp);
  384.     rename_file (newnewsrc, newsrc);
  385.  
  386. subscribe_done:
  387.     ;
  388. }
  389.  
  390.  
  391. void reset_newsrc ()
  392. {
  393.     FILE *fp;
  394.     FILE *newfp;
  395.     char buf[8192];
  396.     char *p;
  397.     char c;
  398.     int i;
  399.  
  400.     if ((newfp = fopen (newnewsrc, "w")) == NULL)
  401.         goto update_done;
  402.  
  403.     if ((fp = fopen (newsrc, "r")) != NULL) {
  404.         while (fgets (buf, sizeof (buf), fp) != NULL) {
  405.             for (p = buf; *p && *p != '\n'; p++)
  406.                 continue;
  407.             *p = '\0';
  408.  
  409.             p = buf;
  410.             while (*p && *p != ' ' && *p != ':' && *p != '!')
  411.                     p++;
  412.             c = *p;
  413.             if (c != '\0')
  414.                 *p++ = '\0';
  415.  
  416.             if (c != '!')
  417.                 c = ':';
  418.  
  419.             fprintf (newfp, "%s%c\n", buf, c);
  420.         }
  421.         fclose (fp);
  422.     }
  423.  
  424.     fclose (newfp);
  425.     rename_file (newnewsrc, newsrc);
  426.  
  427. update_done:
  428.     for (i = 0; i < group_top; i++)
  429.         unread[i] = -1;
  430. }
  431.  
  432.  
  433. void delete_group (group)
  434.     char *group;
  435. {
  436.     FILE *fp;
  437.     FILE *newfp;
  438.     char buf[8192];
  439.     char *p;
  440.     char c;
  441.     int gotit = FALSE;
  442.     FILE *del;
  443.  
  444.     if ((newfp = fopen (newnewsrc, "w")) == NULL)
  445.         goto del_done;
  446.  
  447.     if ((del = fopen (delgroups, "a+")) == NULL)
  448.         goto del_done;
  449.  
  450.     if ((fp = fopen (newsrc, "r")) != NULL) {
  451.         while (fgets (buf, sizeof (buf), fp) != NULL) {
  452.             for (p = buf; *p && *p != '\n'; p++)
  453.                 continue;
  454.             *p = '\0';
  455.  
  456.             p = buf;
  457.             while (*p && *p != ' ' && *p != ':' && *p != '!')
  458.                     p++;
  459.             c = *p;
  460.             if (c != '\0')
  461.                 *p++ = '\0';
  462.  
  463.             if (c != '!')
  464.                 c = ':';
  465.  
  466.             if (strcmp (buf, group) == 0) {
  467.                 fprintf (del, "%s%c%s\n", buf, c, p);
  468.                 gotit = TRUE;
  469.             } else
  470.                 fprintf (newfp, "%s%c%s\n", buf, c, p);
  471.         }
  472.         fclose (fp);
  473.     }
  474.  
  475.     fclose (newfp);
  476.  
  477.     if (! gotit)
  478.         fprintf (del, "%s! \n", group);
  479.  
  480.     fclose (del);
  481.     rename_file (newnewsrc, newsrc);
  482.  
  483. del_done:
  484.     ;
  485. }
  486.  
  487.  
  488. int undel_group ()
  489. {
  490.     FILE *del;
  491.     FILE *newfp;
  492.     FILE *fp;
  493.     char buf[2][8192];
  494.     char *p;
  495.     int which = 0;
  496.     long h;
  497.     extern int cur_groupnum;
  498.     int i, j;
  499.     char c;
  500.  
  501.     if ((del = fopen(delgroups, "r")) == NULL) {
  502.         return FALSE;
  503.     }
  504.  
  505.     unlink(delgroups);
  506.     
  507.     if ((newfp = fopen(delgroups, "w")) == NULL) {
  508.         return FALSE;
  509.     }
  510.  
  511.     buf[0][0] = '\0';
  512.     buf[1][0] = '\0';
  513.  
  514.     while (fgets(buf[which], sizeof (buf[which]), del) != NULL) {
  515.         which = !which;
  516.         if (*buf[which])
  517.             fputs(buf[which], newfp);
  518.     }
  519.  
  520.     fclose(del);
  521.     fclose(newfp);
  522.     which = !which;
  523.  
  524.     if (!*buf[which]) {
  525.         return FALSE;
  526.     }
  527.  
  528.     for (p = buf[which]; *p && *p != '\n'; p++)
  529.         continue;
  530.     *p = '\0';
  531.  
  532.     p = buf[which];
  533.     while (*p && *p != ' ' && *p != ':' && *p != '!')
  534.         p++;
  535.     c = *p;
  536.     if (c != '\0')
  537.         *p++ = '\0';
  538.  
  539.     if (c != '!')
  540.         c = ':';
  541.  
  542.     h = hash_groupname (buf[which]);
  543.  
  544.     for (i = group_hash[h]; i >= 0; i = active[i].next) {
  545.         if (strcmp(buf[which], active[i].name) == 0) {
  546.             for (j = 0; j < group_top; j++)
  547.                 if (my_group[j] == i) {
  548.                     return j;
  549.                 }
  550.  
  551.             active[i].flag &= ~UNSUBSCRIBED;   /* mark that we got it */
  552.             if (c != '!')
  553.                 active[i].flag |= SUBSCRIBED;
  554.  
  555.             if (group_top >= max_active)
  556.                 expand_active ();
  557.             group_top++;
  558.             for (j = group_top; j > cur_groupnum; j--) {
  559.                 my_group[j] = my_group[j-1];
  560.                 unread[j] = unread[j-1];
  561.             }
  562.             my_group[cur_groupnum] = i;
  563.             unread[cur_groupnum] = parse_unread(p, i);
  564.  
  565.             if ((fp = fopen(newsrc, "r")) == NULL) {
  566.                 return FALSE;
  567.             }
  568.             if ((newfp = fopen(newnewsrc, "w")) == NULL) {
  569.                 fclose(fp);
  570.                 return FALSE;
  571.             }
  572.             i = 0;
  573.             while (fgets(buf[!which], sizeof (buf[!which]), fp) != NULL) {
  574.                 for (p = buf[!which]; *p && *p != '\n'; p++)
  575.                     continue;
  576.                 *p = '\0';
  577.  
  578.                 p = buf[!which];
  579.                 while (*p && *p!=' ' && *p != ':' && *p != '!')
  580.                     p++;
  581.                 c = *p;
  582.                 if (c != '\0')
  583.                     *p++ = '\0';
  584.  
  585.                 if (c != '!')
  586.                     c = ':';
  587.  
  588.                 while (i < cur_groupnum) {
  589.                     if (strcmp(buf[!which],
  590.                       active[my_group[i]].name) == 0) {
  591.                         fprintf(newfp, "%s%c%s\n",
  592.                             buf[!which], c, p);
  593.                         goto foo_cont;
  594.                     }
  595.                     i++;
  596.                 }
  597.                 fprintf(newfp, "%s%c%s\n", buf[which], c, p);
  598.                 fprintf(newfp, "%s%c%s\n", buf[!which], c, p);
  599.                 break;
  600. foo_cont:;
  601.             }
  602.  
  603.             while (fgets (buf[!which], sizeof (buf[!which]), fp) != NULL)
  604.                 fputs (buf[!which], newfp);
  605.  
  606.             fclose (newfp);
  607.             fclose (fp);
  608.             rename_file (newnewsrc, newsrc);
  609.             return TRUE;
  610.         }
  611.     }
  612.     return FALSE;
  613. }
  614.  
  615.  
  616. void mark_group_read (group, groupnum)
  617.     char *group;
  618.     int groupnum;            /* index into active[] for this group */
  619. {
  620.     FILE *fp;
  621.     FILE *newfp;
  622.     char buf[8192];
  623.     char *p;
  624.     char c;
  625.  
  626.     if (active[groupnum].max < 2)
  627.         return;
  628.  
  629.     if ((newfp = fopen (newnewsrc, "w")) == NULL)
  630.         goto mark_group_read_done;
  631.  
  632.     if ((fp = fopen (newsrc, "r")) != NULL) {
  633.         while (fgets(buf, sizeof (buf), fp) != NULL) {
  634.             for (p = buf; *p; p++)
  635.                 if (*p == '\n') {
  636.                     *p = '\0';
  637.                     break;
  638.                 }
  639.  
  640.             p = buf;
  641.             while (*p && *p != ' ' && *p != ':' && *p != '!')
  642.                     p++;
  643.             c = *p;
  644.             if (c != '\0')
  645.                 *p++ = '\0';
  646.  
  647.             if (c != '!')
  648.                 c = ':';
  649.  
  650.             if (strcmp (buf, group) == 0) {
  651.                 fprintf (newfp, "%s%c 1-%ld\n", buf, c, active[groupnum].max);
  652.             } else
  653.                 fprintf(newfp, "%s%c%s\n", buf, c, p);
  654.         }
  655.         fclose (fp);
  656.     }
  657.  
  658.     fclose (newfp);
  659.     rename_file (newnewsrc, newsrc);
  660.  
  661. mark_group_read_done:
  662.     ;
  663. }
  664.  
  665.  
  666. void parse_seq(s)
  667.     char *s;
  668. {
  669.     long low, high;
  670.     int i;
  671.  
  672.     while (*s) {
  673.         while (*s && (*s < '0' || *s > '9'))
  674.             s++;
  675.  
  676.         if (*s && *s >= '0' && *s <= '9') {
  677.             low = (long) atol (s);
  678.             while (*s && *s >= '0' && *s <= '9')
  679.                 s++;
  680.             if (*s == '-') {
  681.                 s++;
  682.                 high = (long) atol (s);
  683.                 while (*s && *s >= '0' && *s <= '9')
  684.                     s++;
  685.             }  else
  686.                 high = low;
  687.  
  688.             for (i = 0; i < top; i++)
  689.                 if (arts[i].artnum >= low && arts[i].artnum <= high)
  690.                     arts[i].unread = ART_READ;
  691.         }
  692.     }
  693. }
  694.  
  695. /*
  696.  *  Read the first range from the .newsrc sequencer information.
  697.  *  If the top of the first range is higher than what the active
  698.  *  file claims is the bottom, use it as the new bottom instead.
  699.  */
  700.  
  701. int parse_unread (s, groupnum)
  702.     char *s;
  703.     int groupnum;            /* index for group in active[] */
  704. {
  705.     long low, high;
  706.     long last_high;
  707.     int sum = 0;
  708.     int gotone = FALSE;
  709.     int n;
  710.  
  711.     high = 0;
  712.  
  713.     if (*s) {
  714.         while (*s && (*s < '0' || *s > '9')) {
  715.             s++;
  716.         }    
  717.  
  718.         if (*s && *s >= '0' && *s <= '9') {
  719.             low = (long) atol (s);
  720.             while (*s && *s >= '0' && *s <= '9')
  721.                 s++;
  722.             if (*s == '-') {
  723.                 s++;
  724.                 high = (long) atol (s);
  725.                 while (*s && *s >= '0' && *s <= '9')
  726.                     s++;
  727.             }  else
  728.                 high = low;
  729.             gotone = TRUE;
  730.         }
  731.     }
  732.  
  733.     /* Note that in the active file min will be one greater than max
  734.      * when there are no articles in the spool directory. ie., it is
  735.       * always true that "max - min + 1 = article count (including
  736.       * expired articles)"
  737.       */
  738.  
  739.     if (high < active[groupnum].min - 1)
  740.         high = active[groupnum].min - 1;
  741.  
  742.     while (*s) {
  743.         last_high = high;
  744.  
  745.         while (*s && (*s < '0' || *s > '9'))
  746.             s++;
  747.  
  748.         if (*s && *s >= '0' && *s <= '9') {
  749.             low = (long) atol (s);
  750.             while (*s && *s >= '0' && *s <= '9')
  751.                 s++;
  752.             if (*s == '-') {
  753.                 s++;
  754.                 high = (long) atol (s);
  755.                 while (*s && *s >= '0' && *s <= '9')
  756.                     s++;
  757.             }  else
  758.                 high = low;
  759.  
  760.             if (low > last_high)    /* otherwise seq out of order */
  761.                 sum += (low - last_high) - 1;
  762.         }
  763.     }
  764.  
  765.     if (gotone) {
  766.         if (active[groupnum].max > high)
  767.             sum += active[groupnum].max - high;
  768.         return sum;
  769.     }
  770.  
  771.     n = (int) (active[groupnum].max - active[groupnum].min) + 1;
  772.     
  773.     if (n < 0)
  774.         return -1;
  775.     else
  776.         return (n);
  777. }
  778.  
  779.  
  780. int get_line_unread(group, groupnum)
  781.     char *group;
  782.     int groupnum;                /* index for group in active[] */
  783. {
  784.     FILE *fp;
  785.     char buf[8192];
  786.     char *p;
  787.     int ret = -1;
  788.  
  789.     if ((fp = fopen(newsrc, "r")) == NULL)
  790.         return -1;
  791.  
  792.     while (fgets(buf, sizeof (buf), fp) != NULL) {
  793.         p = buf;
  794.         while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
  795.             p++;
  796.         *p++ = '\0';
  797.         
  798.         if (strcmp (buf, group) != 0)
  799.             continue;
  800.             
  801.         ret = parse_unread (p, groupnum);
  802.         break;
  803.     }
  804.  
  805.     fclose (fp);
  806.     return ret;
  807. }
  808.  
  809.  
  810. void print_seq (fp, groupnum)
  811.     FILE *fp;
  812.     int groupnum;            /* index into active[] for this group */
  813. {
  814.     long int artnum, last_read, artmax;
  815.     int i;
  816.     int flag = FALSE;
  817.     
  818.     assert(top >= 0);
  819.  
  820.       /*
  821.        *  sort into the same order as in the spool area for writing
  822.        *  read article numbers to ~/.newsrc
  823.        */
  824.      if (top > 0)
  825.          qsort ((char *) arts, top, sizeof (struct article_t), artnum_comp);
  826.   
  827.      /*
  828.       * Note that killed and expired articles do not appear in arts[].
  829.       * So, even if top is 0 there may be sequencer info to output.
  830.      */
  831.      if (top > 0 && arts[top-1].artnum > active[groupnum].max)
  832.          artmax = arts[top-1].artnum;
  833.      else
  834.          artmax = active[groupnum].max;
  835.      for (artnum=1, i=0; artnum <= artmax; ++artnum, ++i) {
  836.          assert(i<=top);
  837.          if (i==top || arts[i].unread == ART_READ || artnum != arts[i].artnum) {
  838.               if (flag)
  839.                   fprintf(fp, ",");
  840.               else
  841.                   flag = TRUE;
  842.              fprintf (fp, "%ld", artnum);
  843.  
  844.              while (i < top && arts[i].unread == ART_READ)
  845.                  ++i;
  846.  
  847.              last_read = (i<top ? arts[i].artnum - 1 : artmax);
  848.  
  849.              if (last_read != artnum) {
  850.                  fprintf(fp, "-%ld", last_read);
  851.               }
  852.  
  853.              assert(i <= top);
  854.              if (i == top)
  855.                  break;
  856.              artnum = arts[i].artnum;
  857.           }
  858.       }
  859.   
  860.       fflush (fp);
  861.      if (top == 0)
  862.          return;
  863.  
  864.     /*
  865.      *  resort into required sort order
  866.      */
  867.     switch (sort_art_type) {
  868.         case SORT_BY_NOTHING:        /* already sorted above */
  869.             break;
  870.         case SORT_BY_SUBJ_DESCEND:
  871.         case SORT_BY_SUBJ_ASCEND:
  872.             qsort ((char *) arts, top, sizeof (struct article_t), subj_comp);
  873.             break;
  874.         case SORT_BY_FROM_DESCEND:
  875.         case SORT_BY_FROM_ASCEND:
  876.             qsort ((char *) arts, top, sizeof (struct article_t), from_comp);
  877.             break;
  878.         case SORT_BY_DATE_DESCEND:
  879.         case SORT_BY_DATE_ASCEND:
  880.             qsort ((char *) arts, top, sizeof (struct article_t), date_comp);
  881.             break;
  882.     }
  883. }
  884.  
  885. /*
  886.  *  rewrite .newsrc and position group at specifed position
  887.  */
  888.  
  889. int pos_group_in_newsrc (group, pos)
  890.     char *group;
  891.     int pos;
  892. {
  893.     char sub[1024];
  894.     char unsub[1024];
  895.     char buf[1024];
  896.     char newsgroup[1024];
  897.     extern int cur_groupnum;
  898.     FILE *fp_in, *fp_out;
  899.     FILE *fp_sub, *fp_unsub;
  900.     int repositioned = FALSE;
  901.     int subscribed_pos = 1;
  902.     int group_len;
  903.     int option_line = FALSE;
  904.     int ret_code = FALSE;
  905.  
  906.     if ((fp_in = fopen (newsrc, "r")) == NULL) {
  907.         goto rewrite_group_done;
  908.     }
  909.     if ((fp_out = fopen (newnewsrc, "w")) == NULL) {
  910.         goto rewrite_group_done;
  911.     }
  912.  
  913.     sprintf (sub, "/tmp/.subrc.%d", process_id);
  914.     sprintf (unsub, "/tmp/.unsubrc.%d", process_id);
  915.  
  916.     if ((fp_sub = fopen (sub, "w")) == NULL) {
  917.         goto rewrite_group_done;
  918.     }
  919.     if ((fp_unsub = fopen (unsub, "w")) == NULL) {
  920.         goto rewrite_group_done;
  921.     }
  922.  
  923.     /*
  924.      *  split newsrc into subscribed and unsubscribed to files
  925.      */
  926.     group_len = strlen (group);
  927.  
  928.     while (fgets (buf, sizeof (buf), fp_in) != NULL) {
  929.         if (strncmp (group, buf, group_len) == 0 && buf[group_len] == ':') {
  930.             my_strncpy (newsgroup, buf, sizeof (newsgroup));
  931.         } else if (strchr (buf, ':') != NULL) {
  932.             fprintf (fp_sub, "%s", buf);
  933.         } else if (strchr (buf, '!') != NULL) {
  934.             fprintf (fp_unsub, "%s", buf);
  935.         } else {    /* options line at beginning of .newsrc */
  936.             fprintf (fp_sub, "%s", buf);
  937.             option_line = TRUE;
  938.         }
  939.     }
  940.  
  941.     fclose (fp_in);
  942.     fclose (fp_sub);
  943.     fclose (fp_unsub);
  944.  
  945.     /*
  946.      *  write subscribed groups & position group to newnewsrc
  947.      */
  948.     if ((fp_sub = fopen (sub, "r")) == NULL) {
  949.         unlink (sub);
  950.         goto rewrite_group_done;
  951.     }
  952.     while (fgets (buf, sizeof (buf), fp_sub) != NULL) {
  953.         if (option_line) {
  954.             if (strchr (buf, ':') == NULL && strchr (buf, '!') == NULL) {
  955.                 fprintf (fp_out, "%s", buf);
  956.                 continue;
  957.             } else {
  958.                 option_line = FALSE;
  959.             }
  960.         }
  961.  
  962.         if (pos == subscribed_pos) {
  963.             fprintf (fp_out, "%s\n", newsgroup);
  964.             repositioned = TRUE;
  965.         }
  966.         
  967.         fprintf (fp_out, "%s", buf);
  968.  
  969.         subscribed_pos++;
  970.     }
  971.     if (! repositioned) {
  972.         fprintf (fp_out, "%s\n", newsgroup);
  973.         repositioned = TRUE;
  974.     }
  975.     
  976.     fclose (fp_sub);
  977.      unlink (sub);
  978.  
  979.     /*
  980.      *  write unsubscribed groups to newnewsrc
  981.      */
  982.     if ((fp_unsub = fopen (unsub, "r")) == NULL) {
  983.         unlink (unsub);
  984.         goto rewrite_group_done;
  985.     }
  986.     while (fgets (buf, sizeof (buf), fp_unsub) != NULL) {
  987.         fprintf (fp_out, "%s", buf);
  988.     }
  989.  
  990.     fclose (fp_unsub);
  991.     unlink (unsub);
  992.     fclose (fp_out);
  993.  
  994.     if (repositioned) {
  995.         cur_groupnum = pos;
  996.         rename_file (newnewsrc, newsrc);
  997.         ret_code = TRUE;
  998.     }
  999.  
  1000. rewrite_group_done:
  1001.     return ret_code;
  1002. }
  1003.  
  1004. /*
  1005.  *  mark all orther Xref: articles as read when one article read
  1006.  *  Xref: sitename newsgroup:artnum newsgroup:artnum [newsgroup:artnum ...]
  1007.  */
  1008.  
  1009. void mark_all_xref_read (xref_line)
  1010.     char *xref_line; 
  1011. {
  1012. /*
  1013.     char group[LEN];
  1014.     long artnum;
  1015. */    
  1016.     if (xref_line == (char *) 0) {
  1017.         return;
  1018.     }
  1019.  
  1020.     /*
  1021.      *  check sitename macthes nodename of current machine
  1022.      */
  1023.  
  1024.     /*
  1025.      *  tokenize each pair and update that newsgroup if it
  1026.      *  is in users my_group[].
  1027.      */
  1028.      
  1029. }
  1030.