home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / nn.tar / nn-6.5.1 / sequence.c < prev    next >
C/C++ Source or Header  |  1995-04-29  |  16KB  |  743 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Read presentation sequence file
  5.  */
  6.  
  7. #include "config.h"
  8. #include "debug.h"
  9.  
  10. /* sequence.c */
  11.  
  12. static enter_sequence __APROTO((int mode, group_header *gh));
  13. static void faked_entry __APROTO((char *name, flag_type flag));
  14. static void end_sequence __APROTO((void));
  15. static visit_presentation_file __APROTO((char *directory, char *seqfile, FILE *hook));
  16.  
  17. export group_header *group_sequence;
  18. export char *read_mail = NULL;
  19. export int also_subgroups = 1;
  20. export int hex_group_args = 0;
  21.  
  22. static int seq_break_enabled = 1;    /* !! enabled */
  23. static int ignore_done_flag = 0;     /* % toggle */
  24.  
  25. static group_header *tail_sequence = NULL;
  26. static group_header *final_sequence = NULL;
  27.  
  28. static int gs_more_groups;
  29.  
  30. import group_header *rc_sequence;
  31.  
  32. int
  33. only_folder_args(args)
  34. char **args;
  35. {
  36.     register char *arg;
  37.  
  38.     while ((arg = *args++)) {
  39.     if (*arg == '+' || *arg == '~' || *arg == '/') continue;
  40.     if (file_exist(arg, "fr")) continue;
  41.     return 0;
  42.     }
  43.     return 1;
  44. }
  45.  
  46.  
  47. #define    SHOW_NORMAL    0    /*   : put this in at current pos */
  48. #define    SHOW_FIRST    1    /* < : show these groups first */
  49. #define    SHOW_LAST    2    /* > : show this as late as possible */
  50. #define    IGNORE_ALWAYS    3    /* ! : ignore these groups completely */
  51. #define IGN_UNLESS_RC    4    /* !:X ignore these groups unless in rc */
  52. #define    IGN_UNLESS_NEW    5    /* !:O ignore these groups unless new */
  53. #define IGN_UNL_RC_NEW    6    /* !:U ignore unsubscribed */
  54. #define    IGN_IF_NEW    7    /* !:N ignore these groups if new */
  55.  
  56. #define    SHOW_MODES    " <>!-?*"
  57.  
  58. static int
  59. enter_sequence(mode, gh)
  60. int mode;
  61. group_header *gh;
  62. {
  63. #ifdef SEQ_TEST
  64.     if (Debug & SEQ_TEST && mode != SHOW_NORMAL)
  65.     tprintf("SEQ(%c), %s\n", SHOW_MODES[mode], gh->group_name);
  66. #endif
  67.  
  68.     if (gh->master_flag & M_IGNORE_GROUP) return 0;
  69.     if (ignore_done_flag) {
  70.     if (gh->group_flag & G_SEQUENCE) return 0;
  71.     } else
  72.     if (gh->group_flag & G_DONE) return 0;
  73.  
  74.     switch (mode) {
  75.      case IGN_UNLESS_NEW:
  76.     if ((gh->group_flag & G_NEW) == 0)
  77.         gh->group_flag |= G_DONE;
  78.     return 0;
  79.  
  80.      case IGN_IF_NEW:
  81.     if (gh->group_flag & G_NEW)
  82.         gh->group_flag |= G_DONE;
  83.     return 0;
  84.  
  85.      case IGN_UNL_RC_NEW:
  86.     if (gh->group_flag & G_NEW) return 0;
  87.         if (gh->newsrc_line == NULL || (gh->group_flag & G_UNSUBSCRIBED))
  88.         gh->group_flag |= G_DONE;
  89.     return 0;
  90.  
  91.      case IGN_UNLESS_RC:
  92.         if (gh->newsrc_line == NULL || (gh->group_flag & (G_UNSUBSCRIBED|G_NEW)))
  93.         gh->group_flag |= G_DONE;
  94.     return 0;
  95.  
  96.      case IGNORE_ALWAYS:
  97.     gh->group_flag |= G_DONE;
  98.     return 0;
  99.  
  100.      default:
  101.     gh->group_flag |= G_DONE;
  102.     break;
  103.     }
  104.  
  105.     gh->group_flag |= G_SEQUENCE;
  106.  
  107.     if (gh->master_flag & M_NO_DIRECTORY)
  108.     return 0;        /* for nntidy -s */
  109.  
  110.     switch (mode) {
  111.      case SHOW_FIRST:
  112.     if (tail_sequence) {
  113.         gh->next_group = group_sequence;
  114.         group_sequence = gh;
  115.         break;
  116.     }
  117.  
  118.     /*FALLTHRU*/
  119.      case SHOW_NORMAL:
  120.     if (tail_sequence)
  121.         tail_sequence->next_group = gh;
  122.     else
  123.         group_sequence = gh;
  124.     tail_sequence = gh;
  125.     break;
  126.  
  127.      case SHOW_LAST:
  128.     gh->next_group = final_sequence;
  129.     final_sequence = gh;
  130.     break;
  131.     }
  132.     return 1;
  133. }
  134.  
  135.  
  136. static void
  137. faked_entry(name, flag)
  138. char *name;
  139. flag_type flag;
  140. {
  141.     group_header *gh;
  142.  
  143.     gh = newobj(group_header, 1);
  144.  
  145.     gh->group_name = name;
  146.     gh->group_flag = flag | G_FAKED;
  147.     gh->master_flag = 0;
  148.  
  149.     /* "invent" an unread article for read_news */
  150.     gh->last_article = 1;
  151.     gh->last_db_article = 2;
  152.  
  153.     enter_sequence(SHOW_NORMAL, gh);
  154. }
  155.  
  156. static void
  157. end_sequence()
  158. {
  159.     register group_header *gh, *backp;
  160.     register int seq_ix;
  161.  
  162.     if (tail_sequence)
  163.     tail_sequence->next_group = NULL;
  164.  
  165.     /* set up backward pointers */
  166.  
  167.     backp = NULL;
  168.     seq_ix = 0;
  169.     Loop_Groups_Sequence(gh) {
  170.     gh->preseq_index = ++seq_ix;
  171.     gh->prev_group = backp;
  172.     backp = gh;
  173.     }
  174.  
  175. #ifdef SEQ_DUMP
  176.     if (Debug & SEQ_DUMP) {
  177.     for (gh = group_sequence; gh; gh = gh->next_group)
  178.         tprintf("%s\t", gh->group_name);
  179.     tputc(NL);
  180.  
  181.     nn_exit(0);
  182.     }
  183. #endif
  184.  
  185. }
  186.  
  187.  
  188. #ifdef MAIL_READING
  189. static mail_check()
  190. {
  191.     static group_header mail_group;
  192.     struct stat st;
  193.  
  194.     if (read_mail == NULL) return;
  195.     if (stat(read_mail, &st) < 0) return;
  196.     if (st.st_size == 0 || st.st_mtime < st.st_atime) return;
  197.  
  198.     mail_group.group_name = read_mail;
  199.     gh->group_flag = G_FOLDER | G_MAILBOX | G_FAKED;
  200.     gh->master_flag = 0;
  201.  
  202.     /* "invent" an unread article for read_news */
  203.     gh->last_article = 1;
  204.     gh->last_db_article = 2;
  205.  
  206.  
  207.     if (tail_sequence) {
  208.     mail_group.next_group = group_sequence;
  209.     group_sequence = mail_group;
  210.     } else
  211.     enter_sequence(SHOW_NORMAL, &mail_group);
  212. }
  213. #endif
  214.  
  215.  
  216.  
  217. static int
  218. visit_presentation_file(directory, seqfile, hook)
  219. char *directory, *seqfile;
  220. FILE *hook;
  221. {
  222.     register FILE *sf;
  223.     register c;
  224.     register group_header *gh;
  225.     group_header *mp_group;
  226.     char group[FILENAME], *gname;
  227.     char savefile[FILENAME], *dflt_save, *enter_macro;
  228.     register char *gp;
  229.     int mode, merge_groups;
  230.  
  231.     if (gs_more_groups == 0) return 0;
  232.  
  233.     if (hook != NULL)
  234.     sf = hook;    /* hook to init file */
  235.     else
  236.     if ((sf = open_file(relative(directory, seqfile), OPEN_READ)) == NULL)
  237.         return 0;
  238.  
  239. #ifdef SEQ_TEST
  240.     if (Debug & SEQ_TEST)
  241.     tprintf("Sequence file %s/%s\n", directory, seqfile);
  242. #endif
  243.  
  244.     mode = SHOW_NORMAL;
  245.     savefile[0] = NUL;
  246.     dflt_save = NULL;
  247.  
  248.     while (gs_more_groups) {
  249.  
  250.     if ((c = getc(sf)) == EOF) break;
  251.     if (!isascii(c) || isspace(c)) continue;
  252.  
  253.     switch (c) {
  254.      case '!':
  255.         mode = IGNORE_ALWAYS;
  256.         if ((c = getc(sf)) == EOF) continue;
  257.         if (c == '!') {
  258.         if (seq_break_enabled) {
  259.             fclose(sf);
  260.             return 1;
  261.         }
  262.         mode = SHOW_NORMAL;
  263.         continue;
  264.         }
  265.         if (c == ':') {
  266.         if ((c = getc(sf)) == EOF) continue;
  267.         if (!isascii(c) || isspace(c) || !isupper(c)) continue;
  268.         switch (c) {
  269.          case 'O':
  270.             mode = IGN_UNLESS_NEW;
  271.             continue;
  272.          case 'N':
  273.             mode = IGN_IF_NEW;
  274.             continue;
  275.          case 'U':
  276.             mode = IGN_UNL_RC_NEW;
  277.             continue;
  278.          case 'X':
  279.             mode = IGN_UNLESS_RC;
  280.             continue;
  281.          default:
  282.             /*should give error here*/
  283.             mode = SHOW_NORMAL;
  284.             continue;
  285.         }
  286.         }
  287.         ungetc(c, sf);
  288.         continue;
  289.  
  290.      case '<':
  291.         mode = SHOW_FIRST;
  292.         continue;
  293.  
  294.      case '>':
  295.         mode = SHOW_LAST;
  296.         continue;
  297.  
  298.      case '%':
  299.         ignore_done_flag = ! ignore_done_flag;
  300.         continue;
  301.  
  302.      case '@':
  303.         seq_break_enabled = 0;
  304.         mode = SHOW_NORMAL;
  305.         continue;
  306.  
  307.      case '#':
  308.         do c = getc(sf);
  309.         while (c != EOF && c != NL);
  310.         mode = SHOW_NORMAL;
  311.         continue;
  312.  
  313.     }
  314.  
  315.     gp = group;
  316.     merge_groups = 0;
  317.     do {
  318.         *gp++ = c;
  319.         if (c == ',') merge_groups = 1;
  320.         c = getc(sf);
  321.     } while (c != EOF && isascii(c) && !isspace(c));
  322.  
  323.     *gp = NUL;
  324.  
  325.     while (c != EOF && (!isascii(c) || isspace(c))) c = getc(sf);
  326.     if (c == '+' || c == '~' || c == '/') {
  327.         gp = savefile;
  328.         if (c == '+') {
  329.         c = getc(sf);
  330.         if (c == EOF || (isascii(c) && isspace(c)))
  331.             goto use_same_savefile;
  332.         *gp++ = '+';
  333.         }
  334.         do {
  335.         *gp++ = c;
  336.         c = getc(sf);
  337.         } while (c != EOF && isascii(c) && !isspace(c));
  338.         *gp = NUL;
  339.         dflt_save = savefile[0] ? copy_str(savefile) : NULL;
  340.     } else
  341.         dflt_save = NULL;
  342.  
  343.      use_same_savefile:
  344.     while (c != EOF && (!isascii(c) || isspace(c))) c = getc(sf);
  345.     if (c == '(') {
  346.         enter_macro = parse_enter_macro(sf, getc(sf));
  347.     } else {
  348.         enter_macro = NULL;
  349.         if (c != EOF) ungetc(c, sf);
  350.     }
  351.  
  352.     mp_group = NULL;
  353.     for (gp = group; *gp;) {
  354.         gname = gp;
  355.         if (merge_groups) {
  356.         while (*gp && *gp != ',') gp++;
  357.         if (*gp) *gp++ = NUL;
  358.         }
  359.         start_group_search(gname);
  360.  
  361.         while ((gh = get_group_search())) {
  362.         if (merge_groups && gh->group_flag & G_UNSUBSCRIBED) continue;
  363.  
  364.         if (!enter_sequence(mode, gh)) continue;
  365.  
  366.         if (merge_groups) {
  367.             if (mp_group == NULL) {
  368.             gh->group_flag |= G_MERGE_HEAD;
  369.             } else {
  370.             mp_group->merge_with = gh;
  371.             gh->group_flag |= G_MERGE_SUB;
  372.             }
  373.             mp_group = gh;
  374.         }
  375.  
  376.         if (gh->save_file == NULL) /* not set by "save-files" */
  377.             gh->save_file = dflt_save;
  378.         if (gh->enter_macro == NULL) /* not set by "on entry" */
  379.             gh->enter_macro = enter_macro;
  380.         }
  381.         if (!merge_groups) *gp = NUL;
  382.     }
  383.     if (merge_groups && mp_group != NULL)
  384.         mp_group->merge_with = NULL;
  385.     mode = SHOW_NORMAL;
  386.     }
  387.  
  388.     fclose(sf);
  389.     return 0;
  390. }
  391.  
  392. void
  393. parse_save_files(sf)
  394. register FILE *sf;
  395. {
  396.     register c;
  397.     register group_header *gh;
  398.     char group[FILENAME];
  399.     char *savefile = NULL;
  400.     char namebuf[FILENAME];
  401.     register char *gp;
  402.  
  403.     for (;;) {
  404.     if ((c = getc(sf)) == EOF) break;
  405.     if (!isascii(c) || isspace(c)) continue;
  406.     if (c == '#') {
  407.         do c = getc(sf); while (c != EOF && c != NL);
  408.         continue;
  409.     }
  410.     gp = group;
  411.     do {
  412.         *gp++ = c;
  413.         c = getc(sf);
  414.     } while (c != EOF && isascii(c) && !isspace(c));
  415.     *gp = NUL;
  416.  
  417.     if (strcmp(group, "end") == 0) break;
  418.  
  419.     while (c != EOF && (!isascii(c) || isspace(c))) c = getc(sf);
  420.  
  421.     gp = namebuf;
  422.     do {
  423.         *gp++ = c;
  424.         c = getc(sf);
  425.     } while (c != EOF && isascii(c) && !isspace(c));
  426.     *gp = NUL;
  427.     if (namebuf[0] == NUL) break;
  428.     if (strcmp(namebuf, "+"))
  429.         savefile = copy_str(namebuf);
  430.  
  431.     start_group_search(group);
  432.  
  433.     while ((gh = get_group_search()))
  434.         gh->save_file = savefile;
  435.     }
  436. }
  437.  
  438. void
  439. named_group_sequence(groups)
  440. char **groups;
  441. {
  442.     register group_header *gh;
  443.     register char *group;
  444.     register char *value;
  445.     int non_vars;
  446.     int found, any, errors, gnum;
  447.  
  448.     group_sequence = NULL;
  449.     also_subgroups = 0;
  450.  
  451.     any = errors = 0;
  452.     non_vars = 0;
  453.     while ((group = *groups++)) {
  454.     non_vars++;
  455.  
  456.     if (hex_group_args) {
  457.         sscanf(group, "%x", &gnum);
  458.         if (gnum < 0 || gnum >= master.number_of_groups) continue;
  459.         gh = ACTIVE_GROUP(gnum);
  460.         if (enter_sequence(SHOW_NORMAL, gh)) any++;
  461.         continue;
  462.     }
  463.  
  464.     if ((gh = lookup(group))) {
  465.         if (enter_sequence(SHOW_NORMAL, gh)) any++;
  466.         continue;
  467.     }
  468.  
  469.     if ((value = strchr(group, '='))) {
  470.         *value++ = NUL;
  471.         set_variable(group, 1, value);
  472.         non_vars--;
  473.         continue;
  474.     }
  475.  
  476.     if (*group == '+' || *group == '~' || file_exist(group, "fr")) {
  477.         faked_entry(group, G_FOLDER);
  478.         any++;
  479.         continue;
  480.     }
  481.  
  482. #ifdef NOT_DEF
  483.     if (*group == '+' || *group == '~') {
  484.         char exp_file[FILENAME];
  485.         group_header fake_group;
  486.  
  487.         current_group = &fake_group;
  488.         fake_group.group_name = group;
  489.         group_file_name = NULL;
  490.         if (expand_file_name(exp_file, group, 1) && file_exist(exp_file, "fr")) {
  491.         faked_entry(copy_str(exp_file), G_FOLDER);
  492.         any++;
  493.         continue;
  494.         }
  495.  
  496.         tprintf("Folder %s not found\n", group); fl;
  497.         errors++;
  498.         continue;
  499.     }
  500. #endif
  501.  
  502.     found = 0;
  503.     start_group_search(group);
  504.     while ((gh = get_group_search())) {
  505.         found++;
  506.         enter_sequence(SHOW_NORMAL, gh);
  507.     }
  508.  
  509.     if (!found) {
  510.         tprintf("Group %s not found\n", group); fl;
  511.         errors++;
  512.     } else
  513.         any++;
  514.     }
  515.  
  516.     if (non_vars == 0) {
  517.     normal_group_sequence();
  518.     return;
  519.     }
  520.  
  521.     end_sequence();
  522.  
  523.     if (errors) user_delay(2);
  524.  
  525.     return;
  526. }
  527.  
  528. FILE *loc_seq_hook = NULL;    /* sequence in local "init" file */
  529. FILE *glob_seq_hook = NULL;    /* sequence in global "init" file */
  530.  
  531. void
  532. normal_group_sequence()
  533. {
  534.     register group_header *gh;
  535.  
  536.     group_sequence = NULL;
  537.     gs_more_groups = 1;
  538.  
  539.     /* visit_p_f returns non-zero if terminated by !! */
  540.  
  541.     if (visit_presentation_file(nn_directory, "seq", loc_seq_hook))
  542.     goto final;
  543.  
  544.     if (visit_presentation_file(lib_directory, "sequence", glob_seq_hook))
  545.     goto final;
  546.  
  547.     Loop_Groups_Sorted(gh) {
  548.     enter_sequence(SHOW_NORMAL, gh);
  549.     }
  550.  
  551.  final:
  552.     if (final_sequence)
  553.     if (tail_sequence) {
  554.         tail_sequence->next_group = final_sequence;
  555.         tail_sequence = NULL;
  556.     } else
  557.         group_sequence = final_sequence;
  558.  
  559. #ifdef MAIL_READING
  560.     mail_check();
  561. #endif
  562.  
  563.     end_sequence();
  564. }
  565.  
  566.  
  567.  
  568. static char *gs_group;
  569. static int gs_length, gs_index, gs_mode;
  570. static group_header *gs_only_group = NULL;
  571.  
  572. #define GS_PREFIX0    0    /* group (or group*) */
  573. #define    GS_PREFIX    1    /* group. */
  574. #define    GS_SUFFIX    2    /* .group */
  575. #define GS_INFIX    3    /* .group. */
  576. #define GS_NEW_GROUP    4    /* new group */
  577. #define GS_ALL        5    /* all / . */
  578. #define    GS_NEWSRC    6    /* RC */
  579.  
  580. void
  581. start_group_search(group)
  582. char *group;
  583. {
  584.     char *dot;
  585.     int last;
  586.  
  587.     gs_index = master.number_of_groups;    /* loop will fail */
  588.  
  589.     if ((last = strlen(group) - 1) < 0) return;
  590.     if (group[last] == '*')
  591.     group[last] = NUL;
  592.     else
  593.     if (!also_subgroups && (gs_only_group = lookup(group)) != NULL)
  594.         return;
  595.  
  596.     gs_index = 0;
  597.     gs_more_groups = 0;
  598.     gs_length = 0;
  599.     gs_group = NULL;
  600.  
  601.     if (strcmp(group, "NEW") == 0) {
  602.     gs_mode = GS_NEW_GROUP;
  603.     return;
  604.     }
  605.  
  606.     if (strncmp(group, "RC", 2) == 0) {
  607.     gs_mode = GS_NEWSRC;
  608.     gs_only_group = rc_sequence;
  609.     gs_more_groups = 1;    /* we just can't know! */
  610.  
  611.     if (group[2] != ':') return;
  612.     if (isdigit(group[3]))
  613.         gs_index = atoi(group+3);
  614.     else {
  615.         gs_group = group+3;
  616.         gs_length = strlen(gs_group);
  617.     }
  618.     return;
  619.     }
  620.  
  621.     if (strcmp(group, "all") == 0 || strcmp(group, ".") == 0) {
  622.     gs_mode = GS_ALL;
  623.     return;
  624.     }
  625.  
  626.     gs_mode = GS_PREFIX0;
  627.  
  628.     if (strncmp(group, "all.", 4) == 0) group += 3;
  629.  
  630.     if (*group == '.') gs_mode = GS_SUFFIX;
  631.  
  632.     if ((dot = strrchr(group, '.')) != NULL && dot != group) {
  633.     if (dot[1] == NUL || strcmp(dot+1, "all") == 0) {
  634.         dot[1] = NUL;
  635.         gs_mode = (gs_mode == GS_SUFFIX) ? GS_INFIX : GS_PREFIX;
  636.     }
  637.     }
  638.  
  639.     gs_length = strlen(group);
  640.     gs_group = group;
  641. }
  642.  
  643. #define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, (int)(n)) == 0)
  644.  
  645. group_header *
  646. get_group_search()
  647. {
  648.     register group_header *gh, **ghp;
  649.     register int gsidx = gs_index;        /* cached gs_index (RW) */
  650.     register int mstngrps = master.number_of_groups; /* cached (RO) */
  651.     register int gdonemask = (ignore_done_flag? 0: G_DONE);
  652.     register int tail;
  653.     register int gslen = gs_length;        /* cached (RO) */
  654.     register int gsmgrps = gs_more_groups;    /* cached (RW) */
  655.     register char *ghgrpnm;
  656.     register char *gsgrp = gs_group;    /* cached (RO) */
  657.     register int gsmode = gs_mode;        /* cached (RO) */
  658.     register group_header *gsog = gs_only_group;    /* cached (RW) */
  659.  
  660.     /* most of start up CPU time goes here */
  661.     if (gsmode == GS_NEWSRC) {
  662.     /* gsgrp is usually "" */
  663. #ifdef notdef    /* seemed like a good idea at the time; actually slower */
  664.     if (gslen == 0) {            /* common case */
  665.         if (gsidx != 0)
  666.             --gs_index;
  667.         gs_only_group = NULL;
  668.         return NULL;
  669.     }
  670. #endif
  671.     do {
  672.         gh = gsog;
  673.         if (gh == NULL)
  674.         break;
  675.         if (gsidx && --gsidx == 0)
  676.         gsog = NULL;
  677.         else if (gsgrp && gh->group_name_length >= gslen &&
  678.         strncmp(gh->group_name, gsgrp, gslen) == 0) {
  679.         gsog = NULL;
  680.         } else
  681.         gsog = gh->newsrc_seq;
  682.     } while (gh->group_flag&gdonemask || gh->master_flag&M_IGNORE_GROUP);
  683.     gs_only_group = gsog;
  684.     gs_index = gsidx;
  685.     return gh;
  686.     }
  687.  
  688.     if (gsog != NULL) {
  689.     gh = gsog;
  690.     gs_only_group = NULL;
  691.     if (gh->group_flag&gdonemask || gh->master_flag&M_IGNORE_GROUP)
  692.         return NULL;
  693.     return gh;
  694.     }
  695.  
  696.     for (ghp = &sorted_groups[gsidx]; gsidx < mstngrps; ++ghp) {
  697.     gh = *ghp;
  698.     gsidx++;
  699.     if (gh->group_flag&gdonemask || gh->master_flag&M_IGNORE_GROUP)
  700.         continue;
  701.     gsmgrps++;
  702.     if ((tail = gh->group_name_length - gslen) < 0)
  703.         continue;
  704.  
  705.     ghgrpnm = gh->group_name;
  706.     if (gsmode == GS_PREFIX0) {
  707.         /* the big winner */
  708.         if (((tail = ghgrpnm[gslen]) != NUL && tail != '.') ||
  709.             !STREQN(ghgrpnm, gsgrp, gslen))
  710.             continue;
  711.     } else if (gsmode == GS_PREFIX) {
  712.         if (!STREQN(ghgrpnm, gsgrp, gslen))
  713.         continue;
  714.     } else switch (gsmode) {
  715.      case GS_NEW_GROUP:
  716.         if ((gh->group_flag&G_NEW) == 0 || gh->group_flag&G_UNSUBSCRIBED)
  717.         continue;
  718.         break;
  719.  
  720.      case GS_SUFFIX:
  721.         if (strcmp(ghgrpnm + tail, gsgrp) != 0)
  722.         continue;
  723.         break;
  724.  
  725.      case GS_INFIX:
  726.         nn_exitmsg(1, ".name. notation not supported (yet)");
  727.         break;
  728.  
  729.      case GS_ALL:
  730.         break;
  731.     }
  732.     gsmgrps--;
  733.     gs_more_groups = gsmgrps;
  734.     gs_only_group = gsog;
  735.     gs_index = gsidx;
  736.     return gh;
  737.     }
  738.     gs_more_groups = gsmgrps;
  739.     gs_only_group = gsog;
  740.     gs_index = gsidx;
  741.     return NULL;
  742. }
  743.