This is group.c in view mode; [Download] [Up]
/* Copyright (c) 1995 John E. Davis (davis@space.mit.edu) * All rights reserved. */ #include "config.h" #include "features.h" #include <stdio.h> #include <string.h> #include <time.h> #ifndef VMS # include <sys/types.h> # include <sys/stat.h> #endif #ifdef HAVE_STDLIB_H # include <stdlib.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #include <slang.h> #include "jdmacros.h" /* #include "clientlib.h" */ #include "slrn.h" #include "group.h" #include "art.h" #include "misc.h" #include "post.h" #include "server.h" #include "hash.h" #include "score.h" #include "menu.h" #define GROUP_HASH_TABLE_SIZE 1250 static Slrn_Group_Type *Group_Hash_Table [GROUP_HASH_TABLE_SIZE]; int Slrn_Query_Group_Cutoff = 100; int Slrn_Groups_Dirty; /* greater than 0 if need to write newsrc */ int Slrn_List_Active_File = 0; int Slrn_Use_Xgtitle = 0; int Slrn_Write_Newsrc_Flags = 0; /* if 1, do not save unsubscribed * if 2, do not save new unsubscribed. */ int Slrn_Group_Description_Column = 40;/* column where group descr start */ static Slrn_Group_Type *Groups, *Current_Group; static Slrn_Group_Type *Top_Group; /* group at top of screen */ static Slrn_Group_Type *Bottom_Group; /* group at bottom of screen */ static int Last_Cursor_Row; static int Num_Groups; static int Line_Num; static int Groups_Hidden; /* if true, hide groups with no arts */ int Slrn_Group_Window_Size; /* num rows in group window */ int Slrn_Group_Display_Descriptions = 1; int Slrn_No_Backups = 0; int Slrn_Prompt_Next_Group = 1; static void group_update_screen (void); static void quick_help (void) { if (0 == slrn_message ( "SPC:Select p:Post c:CatchUp l:List q:Quit ^R:Redraw (u)s:(Un)Subscribe")) Slrn_Message_Present = 0; } #if 0 static void slrn_dump_groups (void) { Slrn_Group_Type *g; g = Groups; while (g != NULL) { fprintf (stdout, "%s %d-%d\n", g->name, g->range.min, g->range.max); g = g->next; } fflush (stdout); } #endif /* Note: This routine is NOT very robust. It assumes that this function * is called in an ordered way such that the implied range is always increasing. * This is why the range is re-built in art.c:update_ranges. Yes, it is ugly. * See also slrn_group_mark_article_as_read for something more random. */ void slrn_add_group_ranges (Slrn_Group_Type *g, int min, int max) { Slrn_Range_Type *r, *next; int unread; if ((max < min) || (g == NULL)) return; /* The first one is range of articles on server so expand max to cover * the range of articles nolonger available. */ next = &g->range; if (max < next->min) { /* If we have already expanded the range up to range currently available * at server and we are now trying to add another range below available * range, do not bother. */ if (next->next != NULL) return; max = next->min - 1; } /* Count number unread */ unread = next->max; while (next->next != NULL) { next = next->next; unread -= next->max - next->min + 1; } /* check to see if a merge is possible */ if ((min <= next->max + 1) && (next != &g->range)) { next->max = max; } else { if (NULL == (r = (Slrn_Range_Type *) SLMALLOC (sizeof(Slrn_Range_Type)))) { slrn_exit_error ("Memory allocation error."); } r->next = next->next; next->next = r; r->prev = next; r->min = min; r->max = max; /* For this case, min should be 1 */ if (next == &g->range) { min = r->min = 1; } } unread -= max - min + 1; if (unread < 0) unread = 0; g->unread = unread; Slrn_Groups_Dirty = 1; } static void group_mark_article_as_read (Slrn_Group_Type *g, long num) { Slrn_Range_Type *r, *r1, *newr; r1 = &g->range; if (r1->max < num) /* not at server yet so update our data */ { r1->max = num; g->unread += 1; } r = r1->next; while (r != NULL) { /* Already read */ if ((num <= r->max) && (num >= r->min)) return; if (num < r->min) break; r1 = r; r = r->next; } if (g->unread > 0) g->unread -= 1; Slrn_Groups_Dirty = 1; if ((r != NULL) && (r->min == num + 1)) { r->min = num; return; } if ((r1->max + 1 == num) && (r1 != &g->range)) { r1->max = num; return; } if (NULL == (newr = (Slrn_Range_Type *) SLMALLOC (sizeof (Slrn_Range_Type)))) { slrn_exit_error ("Memory allocation error"); } newr->min = newr->max = num; newr->next = r; if (r != NULL) r->prev = newr; newr->prev = r1; r1->next = newr; } void slrn_mark_article_as_read (char *group, long num) { Slrn_Group_Type *g; unsigned long hash; if (group == NULL) { group_mark_article_as_read (Current_Group, num); return; } hash = slrn_compute_hash ((unsigned char *) group, (unsigned char *) group + strlen (group)); g = Group_Hash_Table[hash % GROUP_HASH_TABLE_SIZE]; while (g != NULL) { if ((g->hash == hash) && !strcmp (group, g->name)) { /* If it looks like we have read this group, mark it read. */ if (((g->flags & GROUP_UNSUBSCRIBED) == 0) || (g->range.next != NULL)) group_mark_article_as_read (g, num); break; } g = g->hash_next; } } static Slrn_Group_Type *find_group_entry (char *name, unsigned int len) { int hash_index; unsigned long hash; Slrn_Group_Type *g; hash = slrn_compute_hash ((unsigned char *) name, (unsigned char *) name + len); hash_index = hash % GROUP_HASH_TABLE_SIZE; g = Group_Hash_Table[hash_index]; while (g != NULL) { if ((g->hash == hash) && !strncmp (name, g->name, len)) { if (len == strlen (g->name)) break;; } g = g->hash_next; } return g; } static Slrn_Group_Type *create_group_entry (char *name, unsigned int len, int min, int max, int query_server, int skip_find) { int hash_index; unsigned long hash; Slrn_Group_Type *g; if (skip_find == 0) { g = find_group_entry (name, len); if (g != NULL) return g; } if (NULL == (g = (Slrn_Group_Type *) SLMALLOC (sizeof (Slrn_Group_Type)))) { slrn_exit_error ("Memory allocation failure."); } SLMEMSET ((char *) g, 0, sizeof (Slrn_Group_Type)); if (len > MAX_GROUP_NAME_LEN) len = MAX_GROUP_NAME_LEN; strncpy (g->name, name, len); g->name [len] = 0; if (query_server) { if (0 != Slrn_Server_Obj->sv_select_group (g->name, &min, &max)) { Slrn_Groups_Dirty = 1; if (Slrn_TT_Initialized == 0) slrn_error ("Group %s is bogus.\r\n", g->name); else slrn_error ("Group %s is bogus.\n", g->name); SLFREE (g); return NULL; } } g->range.min = min; g->range.max = max; if (max > 0) g->unread = max - min + 1; else g->unread = 0; g->flags = (GROUP_UNSUBSCRIBED | GROUP_HIDDEN); hash = slrn_compute_hash ((unsigned char *) name, (unsigned char *) name + len); hash_index = hash % GROUP_HASH_TABLE_SIZE; g->hash = hash; g->hash_next = Group_Hash_Table[hash_index]; Group_Hash_Table[hash_index] = g; if (Groups == NULL) { Current_Group = Groups = g; } else { if (Current_Group == NULL) Current_Group = Groups; g->next = Current_Group->next; if (g->next != NULL) g->next->prev = g; Current_Group->next = g; g->prev = Current_Group; } Current_Group = g; return g; } static int parse_active_line (char *name, unsigned int *lenp, int *minp, int *maxp) { char *p; p = name; while (*p > ' ') p++; *lenp = (unsigned int) (p - name); while (*p == ' ') p++; *maxp = atoi (p); while (*p > ' ') p++; while (*p == ' ') p++; *minp = atoi(p); if (*maxp < *minp) *minp = *maxp + 1; return 0; } static int add_group (char *name, unsigned int len, unsigned int subscribe_flag, int create_flag) { char ch; Slrn_Group_Type *g; g = find_group_entry (name, len); if (g == NULL) { if (Slrn_List_Active_File) { char namebuf[MAX_GROUP_NAME_LEN + 1]; if (len > MAX_GROUP_NAME_LEN) len = MAX_GROUP_NAME_LEN; strncpy (namebuf, name, len); namebuf[len] = 0; fprintf (stderr, "Group %s is bogus, Removing it.\r\n", namebuf); return -1; } else g = create_group_entry (name, len, -1, -1, !(subscribe_flag & GROUP_UNSUBSCRIBED), 0); if (g == NULL) return -1; } Slrn_Groups_Dirty = 1; /* If we have already processed this, then the group is duplicated in * the newsrc file. Throw it out now. */ if (g->flags & GROUP_PROCESSED) return -1; Current_Group = g; g->flags = subscribe_flag; g->flags |= GROUP_PROCESSED; if (subscribe_flag & GROUP_UNSUBSCRIBED) { g->unread = 0; g->flags |= GROUP_HIDDEN; /* if (Slrn_List_Active_File == 0) return 0; */ } if (create_flag) return 0; /* find ranges for this */ name += len; /* skip past name */ if (*name) name++; /* skip colon */ while (1) { int min, max; /* skip white space and delimiters */ while (((ch = *name) != 0) && ((ch <= ' ') || (ch == ','))) name++; if ((ch < '0') || (ch > '9')) break; min = atoi (name++); while (((ch = *name) != 0) && (ch >= '0') && (ch <= '9')) name++; if (ch == '-') { name++; max = atoi (name); while (((ch = *name) != 0) && (ch >= '0') && (ch <= '9')) name++; } else max = min; slrn_add_group_ranges (Current_Group, min, max); } return 0; } static void find_line_num (void) { Slrn_Group_Type *g; int n; n = 1; if (Current_Group == NULL) Current_Group = Groups; /* Move to a group that is not hidden */ while (Current_Group != NULL) { if ((Current_Group->flags & GROUP_HIDDEN) == 0) break; Current_Group = Current_Group->next; } if (Current_Group != NULL) { g = Groups; while (g != Current_Group) { if (0 == (g->flags & GROUP_HIDDEN)) n++; g = g->next; } } else if (Groups_Hidden == 0) { Current_Group = Groups; } Line_Num = n; g = Current_Group; Num_Groups = n - 1; while (g != NULL) { if (0 == (g->flags & GROUP_HIDDEN)) Num_Groups++; g = g->next; } } static void toggle_hide_groups (void) { Slrn_Group_Type *g; int n = 0; Groups_Hidden = !Groups_Hidden; g = Groups; if (Groups_Hidden) { while (g != NULL) { if ((g->unread == 0) && ((g->flags & GROUP_UNSUBSCRIBED) == 0)) g->flags |= GROUP_HIDDEN; g = g->next; } } else { while (g != NULL) { if ((g->unread == 0) && ((g->flags & GROUP_UNSUBSCRIBED) == 0)) g->flags &= ~GROUP_HIDDEN; g = g->next; } } g = Groups; n = 0; while (g != NULL) { if ((g->flags & GROUP_HIDDEN) == 0) n++; g = g->next; } Num_Groups = n; g = Current_Group; while ((g != NULL) && (g->flags & GROUP_HIDDEN)) g = g->next; if ((g == NULL) && (Current_Group != NULL)) { g = Current_Group -> prev; while ((g != NULL) && (g->flags & GROUP_HIDDEN)) g = g->prev; } Current_Group = g; find_line_num (); Top_Group = NULL; Slrn_Full_Screen_Update = 1; } static SLRegexp_Type *read_group_regexp (char *prompt) { static char pattern[256]; if (slrn_read_input (prompt, pattern, 1) <= 0) return NULL; return slrn_compile_regexp_pattern (slrn_fix_regexp (pattern)); } static Slrn_Group_Type *process_xgtitle_info (void) { char buf [NNTP_BUFFER_SIZE]; Slrn_Group_Type *first = NULL, *save = Current_Group; while (Slrn_Server_Obj->sv_read_line(buf, sizeof(buf)) != NULL) { char *b, ch; unsigned int len; Slrn_Group_Type *g; b = buf; while (((ch = *b) != 0) && (ch != ' ') && (ch != '\n') && (ch != '\t')) b++; len = (unsigned int) (b - buf); if (len == 0) continue; *b = 0; g = create_group_entry (buf, len, -1, -1, 0, 0); if (g != NULL) { g->flags &= ~GROUP_HIDDEN; if ((first == NULL) && (g->flags & GROUP_UNSUBSCRIBED)) first = g; } } if (save != Current_Group) { Current_Group = save; find_line_num (); } return first; } static void toggle_list_all_groups1 (int hide_flag) { Slrn_Group_Type *g, *first_found = NULL; int n = 0; static int all_hidden = 1; g = Groups; if (hide_flag != -1) { all_hidden = hide_flag; } else all_hidden = !all_hidden; if (all_hidden) { while (g != NULL) { if (g->flags & GROUP_UNSUBSCRIBED) g->flags |= GROUP_HIDDEN; g = g->next; } } #if 0 else if (prompt == 0) { while (g != NULL) { if (g->flags & GROUP_UNSUBSCRIBED) { g->flags &= ~GROUP_HIDDEN; } g = g->next; } } #endif else { SLRegexp_Type *re; if (NULL == (re = read_group_regexp ("List Groups (e.g., comp*unix*): "))) { all_hidden = 1; return; } if ((Slrn_List_Active_File == 0) && Slrn_Use_Xgtitle && (-1 != Slrn_Server_Obj->sv_xgtitle_cmd ((char *) re->pat))) { first_found = process_xgtitle_info (); } else while (g != NULL) { if (g->flags & GROUP_UNSUBSCRIBED) { if (NULL != slrn_regexp_match (re, g->name)) { if (first_found == NULL) first_found = g; g->flags &= ~GROUP_HIDDEN; } } g = g->next; } } g = Groups; n = 0; while (g != NULL) { if ((g->flags & GROUP_HIDDEN) == 0) n++; g = g->next; } Num_Groups = n; g = Current_Group; if (first_found != NULL) { g = first_found; } else { while ((g != NULL) && (g->flags & GROUP_HIDDEN)) g = g->next; if ((g == NULL) && (Current_Group != NULL)) { g = Current_Group -> prev; while ((g != NULL) && (g->flags & GROUP_HIDDEN)) g = g->prev; } } Current_Group = g; if (g != NULL) { g = Groups; n = 1; while (g != Current_Group) { if (0 == (g->flags & GROUP_HIDDEN)) n++; g = g->next; } } else n = 1; Top_Group = NULL; Slrn_Full_Screen_Update = 1; if ((all_hidden == 0) && (Current_Group == NULL)) { Current_Group = Groups; if ((Current_Group != NULL) && (Current_Group->flags & GROUP_HIDDEN)) { Current_Group = NULL; } n = 1; } Line_Num = n; } static int find_group (char *name) { Slrn_Group_Type *g = find_group_entry (name, strlen (name)); if (g == NULL) return 0; g->flags &= ~GROUP_HIDDEN; Current_Group = g; find_line_num (); return 1; } static void group_search (void) { static char search_str[256]; SLsearch_Type st; Slrn_Group_Type *g; int n = 0, wrapped = 0; g = Current_Group; if (g == NULL) return; if (slrn_read_input ("Search: ", search_str, 1) <= 0) return; SLsearch_init (search_str, 1, 0, &st); do { g = g->next; if (g == NULL) { g = Groups; n = 0; wrapped = 1; } if ((g->flags & GROUP_HIDDEN) == 0) { n++; if (NULL != SLsearch ((unsigned char *) g->name, (unsigned char *) g->name + strlen (g->name), &st)) { break; } } } while (g != Current_Group); if (g == Current_Group) slrn_error ("Not found."); else { Current_Group = g; if (wrapped) { Line_Num = 0; slrn_message ("Search wrapped."); } Line_Num += n; } } static void add_group_cmd (void) { char group[256]; *group = 0; if (slrn_read_input ("Add group: ", group, 1) > 0) { if (!find_group (group) && (Slrn_List_Active_File == 0)) add_group (group, strlen (group), 0, 0); Slrn_Groups_Dirty = 1; Slrn_Full_Screen_Update = 1; } } static void catch_up_for_real (void) { Slrn_Range_Type *r, *rnext; if (Current_Group == NULL) return; r = Current_Group->range.next; while (r != NULL) { rnext = r->next; SLFREE (r); r = rnext; } Current_Group->range.next = NULL; slrn_add_group_ranges (Current_Group, 1, Current_Group->range.max); Current_Group->flags |= GROUP_TOUCHED; slrn_message ("Group marked as read."); } /* TODO: check for write errors!!! */ int slrn_write_newsrc (void) { Slrn_Group_Type *g; Slrn_Range_Type *r; char file[SLRN_MAX_PATH_LEN], backup_file[SLRN_MAX_PATH_LEN]; static FILE *fp; int pass; int max; #ifdef unix # ifndef __os2__ struct stat filestat; int stat_worked; # endif #endif slrn_init_hangup_signals (0); if (Slrn_Groups_Dirty == 0) { slrn_init_hangup_signals (1); return 0; } /* In case of hangup and we were writing the file, make sure it is closed. * This will not hurt since we are going to do it again anyway. */ if (fp != NULL) slrn_fclose (fp); fp = NULL; slrn_message ("Writing %s...", Slrn_Newsrc_File); slrn_smg_refresh (); slrn_make_home_filename (Slrn_Newsrc_File, file); #ifdef unix # ifndef __os2__ /* Try to preserve .newsrc permissions and owner/group */ stat_worked = (-1 != stat (file, &filestat)); # endif #endif if (Slrn_No_Backups == 0) { #ifdef VMS sprintf (backup_file, "%s-bak", file); #else sprintf (backup_file, "%s~", file); #endif (void) slrn_delete_file (backup_file); (void) rename (file, backup_file); } if (NULL == (fp = fopen (file, "w"))) { slrn_error ("Unable to save to file %s.", file); if (Slrn_No_Backups == 0) (void) rename (backup_file, file); slrn_init_hangup_signals (1); return -1; } /* We are going to do this in 2 passes. The first pass writes out just * the subscribed groups. The second pass takes care of the rest. */ for (pass = 0; pass < 2; pass++) { g = Groups; while (g != NULL) { if (pass == 0) { if (g->flags & GROUP_UNSUBSCRIBED) { g = g->next; continue; } fputs (g->name, fp); putc (':', fp); } else if (pass == 1) { if ((g->flags & GROUP_UNSUBSCRIBED) == 0) { g = g->next; continue; } if (Slrn_Write_Newsrc_Flags) { if ((Slrn_Write_Newsrc_Flags == 1) || ((Slrn_Write_Newsrc_Flags == 2) && (g->range.next == NULL))) { g = g->next; continue; } } fputs (g->name, fp); putc ('!', fp); } r = g->range.next; max = g->range.max; if (r != NULL) { putc (' ', fp); while (1) { /* Make this check because the unsubscribed group * range may not have been initialized from the server. */ if ((max != -1) && (g->range.min != -1) && ((g->flags & GROUP_UNSUBSCRIBED) == 0)) { if (r->min > max) break; if (r->max > max) r->max = max; } if (r->min != r->max) { fprintf (fp, "%d-%d", r->min, r->max); } else fprintf (fp, "%d", r->min); r = r->next; if (r == NULL) break; putc (',', fp); } } putc ('\n', fp); g = g->next; } } slrn_fclose (fp); fp = NULL; #ifdef unix # ifndef __os2__ /* Try to preserve .newsrc permissions and owner/group */ if (stat_worked) { if (-1 == chmod (file, filestat.st_mode & 0777)) (void) chmod (file, 0600); (void) chown (file, filestat.st_uid, filestat.st_gid); } else (void) chmod (file, 0600 ); # endif #endif Slrn_Groups_Dirty = 0; if (Slrn_TT_Initialized & 1) slrn_message ("Writing %s... done.", Slrn_Newsrc_File); slrn_init_hangup_signals (1); return 0; } static void free_all_groups (void) { Slrn_Group_Type *g = Groups; Slrn_Group_Type *nextg; Slrn_Range_Type *r, *rnext; int i; while (g != NULL) { nextg = g->next; if (g->descript != NULL) SLFREE (g->descript); r = g->range.next; while (r != NULL) { rnext = r->next; SLFREE (r); r = rnext; } SLFREE(g); g = nextg; } Groups = NULL; Current_Group = NULL; Top_Group = Bottom_Group = NULL; Num_Groups = Line_Num = 0; for (i = 0; i < GROUP_HASH_TABLE_SIZE; i++) Group_Hash_Table[i] = NULL; } static void save_newsrc (void) { if (Slrn_Groups_Dirty) { slrn_write_newsrc (); } else { slrn_message ("No changes need to be saved."); } slrn_smg_refresh (); } static void refresh_groups (void) { char name[MAX_GROUP_NAME_LEN + 1]; *name = 0; if (Current_Group != NULL) strcpy (name, Current_Group->name); slrn_set_suspension (1); save_newsrc (); free_all_groups (); /* * Groups_Hidden gets toggled in slrn_read_newsrc, which gets called * in slrn_get_new_news. Therefore, pre-toggle Groups_Hidden ahead of * time. */ Groups_Hidden = !Groups_Hidden; if (-1 == slrn_get_new_news (1, 0)) { slrn_quit (0); } if (*name) (void) find_group (name); slrn_set_suspension (0); quick_help (); } typedef struct Unsubscribed_Slrn_Group_Type { char name[MAX_GROUP_NAME_LEN + 1]; struct Unsubscribed_Slrn_Group_Type *next; } Unsubscribed_Slrn_Group_Type; static Unsubscribed_Slrn_Group_Type *Unsubscribed_Groups; static void add_unsubscribed_group (char *name) { Unsubscribed_Slrn_Group_Type *g; char *p; unsigned int len; if (NULL == (g = (Unsubscribed_Slrn_Group_Type *) SLMALLOC (sizeof (Unsubscribed_Slrn_Group_Type)))) { slrn_exit_error ("Memory allocation error."); } g->next = Unsubscribed_Groups; Unsubscribed_Groups = g; p = name; while (*p > ' ') p++; *p = 0; len = p - name; if (len > MAX_GROUP_NAME_LEN) len = MAX_GROUP_NAME_LEN; strncpy (g->name, name, len); g->name[len] = 0; } static int group_up_n (int n) { Slrn_Group_Type *g; int i; g = Current_Group; i = 0; if (g != NULL) while (i < n) { g = g->prev; while ((g != NULL) && (g->flags & GROUP_HIDDEN)) { g = g->prev; } if (g == NULL) break; i++; Line_Num--; Current_Group = g; } return i; } static void group_up (void) { if (0 == group_up_n (1)) { slrn_error ("Top of buffer."); } } static int group_down_n (int n) { Slrn_Group_Type *g; int i; g = Current_Group; i = 0; if (g != NULL) while (i < n) { g = g->next; while ((g != NULL) && (g->flags & GROUP_HIDDEN)) { g = g->next; } if (g == NULL) break; Line_Num++; Current_Group = g; i++; } return i; } static void group_down (void) { if (1 != group_down_n (1)) { slrn_error ("End of Buffer."); } } static void transpose_groups (void) { Slrn_Group_Type *g = Current_Group, *g1, *tmp; if (g == NULL) return; if (1 != group_up_n (1)) { return; } g1 = Current_Group; tmp = g1->next; /* Two cases to consider */ if (tmp != g) { g1->next = g->next; if (g1->next != NULL) g1->next->prev = g1; g->next = tmp; tmp->prev = g; /* tmp cannot be NULL */ tmp = g1->prev; g1->prev = g->prev; g1->prev->next = g1; /* g1->prev cannot be NULL */ g->prev = tmp; if (tmp != NULL) tmp->next = g; } else /* g1->next == g, g->prev == g1 */ { g->prev = g1->prev; if (g->prev != NULL) g->prev->next = g; g1->next = g->next; if (g1->next != NULL) g1->next->prev = g1; g->next = g1; g1->prev = g; } if (g1 == Groups) Groups = g; find_line_num (); (void) group_down_n (1); Slrn_Full_Screen_Update = 1; Slrn_Groups_Dirty = 1; } static void move_group_cmd (void) { SLang_Key_Type *key; void (*f)(void); Slrn_Group_Type *g; if (Current_Group == NULL) return; g = Current_Group; while (1) { slrn_message ("Moving %s. Press RETURN when finished.", Current_Group->name); slrn_smg_refresh (); key = SLang_do_key (Slrn_Group_Keymap, (int (*)(void)) SLang_getkey); if ((key == NULL) || (key->type == SLKEY_F_INTERPRET)) f = NULL; else f = (void (*)(void)) key->f.f; if (f == group_up) { transpose_groups (); if (2 != group_up_n (2)) return; } else if (f == group_down) { if (1 != group_down_n (1)) return; transpose_groups (); if (1 != group_up_n (1)) return; } else return; if (g != Current_Group) { Current_Group = g; find_line_num (); } group_update_screen (); slrn_smg_refresh (); } } static void subscribe (void) { SLRegexp_Type *re; Slrn_Group_Type *g; if (Current_Group == NULL) return; if (Slrn_Prefix_Arg_Ptr == NULL) { Current_Group->flags &= ~GROUP_UNSUBSCRIBED; Current_Group->flags |= GROUP_TOUCHED; group_down_n (1); Slrn_Groups_Dirty = 1; return; } Slrn_Prefix_Arg_Ptr = NULL; if (NULL == (re = read_group_regexp ("Subscribe pattern: "))) return; g = Groups; while (g != NULL) { if (g->flags & GROUP_UNSUBSCRIBED) { if (NULL != slrn_regexp_match (re, g->name)) { g->flags &= ~GROUP_HIDDEN; g->flags &= ~GROUP_UNSUBSCRIBED; g->flags |= GROUP_TOUCHED; } } g = g->next; } find_line_num (); Slrn_Full_Screen_Update = 1; } static void catch_up (void) { if (Current_Group == NULL) return; if (Slrn_User_Wants_Confirmation && slrn_get_yesno(1, "Mark %s as read", Current_Group->name) <= 0) return; catch_up_for_real (); (void) group_down_n (1); } static void uncatch_up (void) { Slrn_Range_Type *r, *rnext; if (Current_Group == NULL) return; if (Slrn_User_Wants_Confirmation && slrn_get_yesno(1, "Mark %s as un-read", Current_Group->name) <= 0) return; r = Current_Group->range.next; while (r != NULL) { rnext = r->next; SLFREE (r); r = rnext; } Current_Group->range.next = NULL; slrn_add_group_ranges (Current_Group, 1, 1); Current_Group->flags |= GROUP_TOUCHED; slrn_message ("Group marked as un-read."); (void) group_down_n (1); } static void unsubscribe (void) { SLRegexp_Type *re; Slrn_Group_Type *g; if (Current_Group == NULL) return; if (Slrn_Prefix_Arg_Ptr == NULL) { Current_Group->flags |= GROUP_UNSUBSCRIBED | GROUP_TOUCHED; group_down_n (1); Slrn_Groups_Dirty = 1; return; } Slrn_Prefix_Arg_Ptr = NULL; if (NULL == (re = read_group_regexp ("Un-Subscribe pattern: "))) return; g = Groups; while (g != NULL) { if ((g->flags & GROUP_UNSUBSCRIBED) == 0) { if (NULL != (slrn_regexp_match (re, g->name))) { g->flags &= ~GROUP_HIDDEN; g->flags |= (GROUP_TOUCHED | GROUP_UNSUBSCRIBED); } } g = g->next; } find_line_num (); Slrn_Full_Screen_Update = 1; } SLKeyMap_List_Type *Slrn_Group_Keymap; int *Slrn_Prefix_Arg_Ptr; void slrn_set_prefix_argument (int rep) { static int repeat; repeat = rep; Slrn_Prefix_Arg_Ptr = &repeat; } void slrn_digit_arg (SLKeyMap_List_Type *kmap) { char buf[20]; unsigned char key; int i; i = 0; buf[i++] = (char) SLang_Last_Key_Char; while(1) { buf[i] = 0; key = (unsigned char) SLang_getkey (); if ((key < '0') || (key > '9')) break; buf[i++] = (char) key; } slrn_set_prefix_argument (atoi (buf)); SLang_ungetkey (key); slrn_do_key (kmap); Slrn_Prefix_Arg_Ptr = NULL; } static void digit_arg (void) { slrn_digit_arg (Slrn_Group_Keymap); } static int group_sync_group_with_server (Slrn_Group_Type *g, int *minp, int *maxp) { int min, max, n, max_available; char *group; Slrn_Range_Type *r; if (g == NULL) return -1; group = g->name; slrn_message ("Selecting %s...", group); slrn_smg_refresh (); slrn_set_suspension (1); if (Slrn_Server_Obj->sv_select_group (group, minp, maxp) < 0) { g->flags &= ~GROUP_UNSUBSCRIBED; slrn_error ("This group appears to be bogus."); slrn_set_suspension (0); return -1; } slrn_set_suspension (0); min = *minp; max = *maxp; if (max == 0) { int nmax, nmin; nmax = g->range.max; nmin = g->range.min; /* Server database inconsistent. */ for (n = nmin; n <= nmax; n++) group_mark_article_as_read (g, n); /* g->unread = 0; */ slrn_message ("No articles to read."); Slrn_Full_Screen_Update = 1; Slrn_Groups_Dirty = 1; return -1; } g->range.min = min; if (max < g->range.max) { /* There is only one way for this to happen that I am aware of: * an article has been cancelled-- update the ranges. */ int nmax = g->range.max; for (n = max + 1; n <= nmax; n++) group_mark_article_as_read (g, n); } else g->range.max = max; /* In case more articles arrived at the server between the time that * slrn was first started and when the server was just queried, update * the ranges of read/unread articles. */ max_available = g->range.max - g->range.min + 1; r = &g->range; if (r->next != NULL) { if (r->next->min <= r->min) r->next->min = 1; n = r->max; while (r->next != NULL) { r = r->next; n -= r->max - r->min + 1; } if (n < 0) n = 0; if (n > max_available) n = max_available; g->unread = n; } return 0; } static void group_select_group (void) { int min, max, n, max_available; int ret; Slrn_Range_Type *r; int prefix; if (Slrn_Prefix_Arg_Ptr != NULL) { prefix = *Slrn_Prefix_Arg_Ptr; Slrn_Prefix_Arg_Ptr = NULL; } else prefix = 0; if (-1 == group_sync_group_with_server (Current_Group, &min, &max)) return; n = Current_Group->unread; max_available = Current_Group->range.max - Current_Group->range.min + 1; if ((prefix & 1) || (n == 0)) n = max_available; if ((prefix & 1) || ((n > Slrn_Query_Group_Cutoff) && (Slrn_Query_Group_Cutoff > 0))) { char int_prompt_buf[256]; sprintf (int_prompt_buf, "%s: Read how many?", Current_Group->name); if ((-1 == slrn_read_integer (int_prompt_buf, &n, &n)) || (n <= 0)) { slrn_clear_message (); Slrn_Full_Screen_Update = 1; return; } if ((0 == (prefix & 1)) && (Current_Group->unread != 0)) { r = Current_Group->range.next; if (r != NULL) { while (r->next != NULL) r = r->next; if (r->max + n > max) n = -n; /* special treatment in article mode * because we will need to query the * server about articles in a group * that we have already read. */ } } } else if ((0 == (prefix & 1)) && (Current_Group->unread != 0)) n = 0; ret = slrn_select_article_mode (Current_Group, n, ((prefix & 2) == 0)); if (ret == -2) catch_up_for_real (); } void slrn_select_next_group (void) { if (Current_Group == NULL) return; while (1 == group_down_n (1)) { if (Current_Group->unread == 0) continue; group_select_group (); break; #if 0 if (Slrn_Current_Mode->mode == SLRN_ARTICLE_MODE) break; #endif } } void slrn_select_prev_group (void) { } void slrn_post_cmd (void) { int ret; char *name, *dist = NULL; /* "world"; */ char group[256]; char subj[256]; if (Slrn_Post_Obj->po_can_post == 0) { slrn_error ("Posting not allowed."); return; } if (Slrn_User_Wants_Confirmation && (slrn_get_yesno (1, "Are you sure that you want to post") <= 0)) return; if (Current_Group == NULL) name = ""; else name = Current_Group->name; strcpy (group, name); if (slrn_read_input ("Newsgroup: ", group, 1) <= 0) return; *subj = 0; if (slrn_read_input ("Subject: ", subj, 1) <= 0) return; ret = slrn_post (group, subj, dist); if (ret < 0) { slrn_error ("Posting failed."); } } void slrn_group_quit (void) { if (Slrn_User_Wants_Confirmation && (slrn_get_yesno (1, "Do you really want to quit") <= 0)) return; if (Slrn_Groups_Dirty) slrn_write_newsrc (); slrn_quit (0); } #if 0 static void group_refresh (void) { if (Slrn_Groups_Dirty) slrn_write_newsrc (); Slrn_Hangup_Hook = NULL; slrn_quit (2); } #endif static void group_pageup (void) { Slrn_Group_Type *g; int n; if (Top_Group != NULL) { Slrn_Full_Screen_Update = 1; /* Move to top of window, then go up one page */ n = 0; g = Current_Group; while ((g != Top_Group) && (g != NULL)) { g = g->prev; if (0 == (g->flags & GROUP_HIDDEN)) n++; } if (g != NULL) { Current_Group = g; Line_Num -= n; n = Line_Num; /* save this */ /* Now compute new top group */ group_up_n (Slrn_Group_Window_Size - 1); Top_Group = Current_Group; Current_Group = g; Line_Num = n; return; } } if (0 == group_up_n (Slrn_Group_Window_Size - 1)) slrn_error ("Top of Buffer."); } static void group_pagedown (void) { Slrn_Group_Type *g; int n; if (Bottom_Group != NULL) { Slrn_Full_Screen_Update = 1; n = 0; g = Current_Group; while ((g != Bottom_Group) && (g != NULL)) { g = g->next; if (0 == (g->flags & GROUP_HIDDEN)) n++; } if (g != NULL) { Top_Group = Current_Group = g; Line_Num += n; return; } } if (0 == group_down_n (Slrn_Group_Window_Size - 1)) slrn_error ("End of Buffer."); } static void group_bob (void) { while (group_up_n (1000)); } static void group_eob (void) { while (group_down_n (1000)); } static void toggle_list_all_groups (void) { int mode; if (Slrn_Prefix_Arg_Ptr != NULL) mode = 1; else mode = -1; toggle_list_all_groups1 (mode); } static void toggle_group_display (void) { Slrn_Group_Display_Descriptions = !Slrn_Group_Display_Descriptions; Slrn_Full_Screen_Update = 1; } void slrn_repeat_last_key (void) { SLtt_beep (); } static void toggle_scoring (void) { switch (slrn_get_response ("FfSsNnCc", "Select scoring mode: F-ull, S-imple, N-one, C-ancel")) { case 'F': case 'f': Slrn_Perform_Scoring = SLRN_XOVER_SCORING | SLRN_EXPENSIVE_SCORING; slrn_message ("Full Header Scoring enabled."); break; case 'S': case 's': Slrn_Perform_Scoring = SLRN_XOVER_SCORING; slrn_message ("Expensive Scoring disabled."); break; case 'N': case 'n': Slrn_Perform_Scoring = 0; slrn_message ("Scoring disabled."); break; default: slrn_clear_message (); break; } } #define A_KEY(s, f) {s, (int (*)(void)) f} static SLKeymap_Function_Type Group_Functions [] = { A_KEY("move_group", move_group_cmd), A_KEY("uncatch_up", uncatch_up), A_KEY("toggle_scoring", toggle_scoring), A_KEY("toggle_group_display", toggle_group_display), A_KEY("refresh_groups", refresh_groups), A_KEY("save_newsrc", save_newsrc), A_KEY("group_search", group_search), A_KEY("group_search_forward", group_search), A_KEY("toggle_list_all", toggle_list_all_groups), A_KEY("add_group", add_group_cmd), A_KEY("bob", group_bob), A_KEY("catchup", catch_up), A_KEY("down", group_down), A_KEY("eob", group_eob), A_KEY("help", slrn_group_help), A_KEY("pagedown", group_pagedown), A_KEY("pageup", group_pageup), A_KEY("post", slrn_post_cmd), A_KEY("quit", slrn_group_quit), A_KEY("redraw", slrn_redraw), A_KEY("select_group", group_select_group), A_KEY("subscribe", subscribe), A_KEY("suspend", slrn_suspend_cmd), A_KEY("toggle_hidden", toggle_hide_groups), A_KEY("unsubscribe", unsubscribe), A_KEY("up", group_up), A_KEY("repeat_last_key", slrn_repeat_last_key), A_KEY("transpose_groups", transpose_groups), A_KEY(NULL, NULL) }; /* actions for different regions: * - top status line (help) * - normal region * - bottom status line */ static void group_mouse (void (*top_status)(void), void (*bot_status)(void), void (*normal_region)(void) ) { int r,c; slrn_get_mouse_rc (&r, &c); /* take top status line into account */ if (r == 1) { if (Slrn_Use_Mouse) slrn_execute_menu (c, Group_Functions); else if (NULL != top_status) (*top_status) (); return; } if (r >= SLtt_Screen_Rows) return; /* bottom status line */ if (r == SLtt_Screen_Rows - 1) { if (NULL != bot_status) (*bot_status) (); return; } r -= (1 + Last_Cursor_Row); if (r < 0) { r = -r; if (r != group_up_n (r)) return; } else if (r != group_down_n (r)) return; if (NULL != normal_region) (*normal_region) (); } static void group_mouse_left (void) { group_mouse (slrn_group_help, group_pagedown, group_select_group); } static void group_mouse_middle (void) { group_mouse (toggle_group_display, toggle_hide_groups, group_select_group); #if 1 /* Make up for buggy rxvt which have problems with the middle key. */ if (NULL != getenv ("COLORTERM")) { if (SLang_input_pending (7)) { while (SLang_input_pending (0)) SLang_getkey (); } } #endif } static void group_mouse_right (void) { group_mouse (slrn_group_help, group_pageup, group_select_group); } static void slrn_group_hup (int sig) { slrn_write_newsrc (); slrn_quit (sig); } static Slrn_Mode_Type Group_Mode_Cap = { NULL, group_update_screen, /* redraw */ NULL, /* sig winch hook */ slrn_group_hup, /* hangup hook */ SLRN_GROUP_MODE }; void slrn_init_group_mode (void) { char *err = "Unable to create group keymap!"; if (NULL == (Slrn_Group_Keymap = SLang_create_keymap ("group", NULL))) slrn_exit_error (err); Group_Mode_Cap.keymap = Slrn_Group_Keymap; Slrn_Group_Keymap->functions = Group_Functions; SLkm_define_key ("\0331", (FVOID_STAR) digit_arg, Slrn_Group_Keymap); SLkm_define_key ("\0332", (FVOID_STAR) digit_arg, Slrn_Group_Keymap); SLkm_define_key ("\0333", (FVOID_STAR) digit_arg, Slrn_Group_Keymap); SLkm_define_key ("\0334", (FVOID_STAR) digit_arg, Slrn_Group_Keymap); SLkm_define_key ("\0335", (FVOID_STAR) digit_arg, Slrn_Group_Keymap); SLkm_define_key ("\0336", (FVOID_STAR) digit_arg, Slrn_Group_Keymap); SLkm_define_key ("\0337", (FVOID_STAR) digit_arg, Slrn_Group_Keymap); SLkm_define_key ("\0338", (FVOID_STAR) digit_arg, Slrn_Group_Keymap); SLkm_define_key ("\0339", (FVOID_STAR) digit_arg, Slrn_Group_Keymap); SLkm_define_key ("\0330", (FVOID_STAR) digit_arg, Slrn_Group_Keymap); SLkm_define_key ("^K\033[A", (FVOID_STAR) group_bob, Slrn_Group_Keymap); SLkm_define_key ("^K\033OA", (FVOID_STAR) group_bob, Slrn_Group_Keymap); SLkm_define_key ("^K\033[B", (FVOID_STAR) group_eob, Slrn_Group_Keymap); SLkm_define_key ("^K\033OB", (FVOID_STAR) group_eob, Slrn_Group_Keymap); SLkm_define_key ("\033A", (FVOID_STAR) toggle_group_display, Slrn_Group_Keymap); SLkm_define_key ("\033>", (FVOID_STAR) group_eob, Slrn_Group_Keymap); SLkm_define_key ("\033<", (FVOID_STAR) group_bob, Slrn_Group_Keymap); SLkm_define_key ("^D", (FVOID_STAR) group_pagedown, Slrn_Group_Keymap); SLkm_define_key ("^V", (FVOID_STAR) group_pagedown, Slrn_Group_Keymap); #ifdef __os2__ SLkm_define_key ("^@Q", (FVOID_STAR) group_pagedown, Slrn_Group_Keymap); SLkm_define_key ("\xE0Q", (FVOID_STAR) group_pagedown, Slrn_Group_Keymap); SLkm_define_key ("^@I", (FVOID_STAR) group_pageup, Slrn_Group_Keymap); SLkm_define_key ("\xE0I", (FVOID_STAR) group_pageup, Slrn_Group_Keymap); #else SLkm_define_key ("\033[6~", (FVOID_STAR) group_pagedown, Slrn_Group_Keymap); SLkm_define_key ("\033[5~", (FVOID_STAR) group_pageup, Slrn_Group_Keymap); #endif SLkm_define_key ("m", (FVOID_STAR) move_group_cmd, Slrn_Group_Keymap); SLkm_define_key ("^U", (FVOID_STAR) group_pageup, Slrn_Group_Keymap); SLkm_define_key ("\033V", (FVOID_STAR) group_pageup, Slrn_Group_Keymap); SLkm_define_key ("a", (FVOID_STAR) add_group_cmd, Slrn_Group_Keymap); SLkm_define_key ("u", (FVOID_STAR) unsubscribe, Slrn_Group_Keymap); SLkm_define_key ("s", (FVOID_STAR) subscribe, Slrn_Group_Keymap); SLkm_define_key ("\033u", (FVOID_STAR) uncatch_up, Slrn_Group_Keymap); SLkm_define_key ("c", (FVOID_STAR) catch_up, Slrn_Group_Keymap); SLkm_define_key ("K", (FVOID_STAR) toggle_scoring, Slrn_Group_Keymap); SLkm_define_key ("L", (FVOID_STAR) toggle_list_all_groups, Slrn_Group_Keymap); SLkm_define_key ("l", (FVOID_STAR) toggle_hide_groups, Slrn_Group_Keymap); SLkm_define_key ("^Z", (FVOID_STAR) slrn_suspend_cmd, Slrn_Group_Keymap); SLkm_define_key (" ", (FVOID_STAR) group_select_group, Slrn_Group_Keymap); SLkm_define_key (".", (FVOID_STAR) slrn_repeat_last_key, Slrn_Group_Keymap); SLkm_define_key ("P", (FVOID_STAR) slrn_post_cmd, Slrn_Group_Keymap); SLkm_define_key ("?", (FVOID_STAR) slrn_group_help, Slrn_Group_Keymap); SLkm_define_key ("\r", (FVOID_STAR) group_select_group, Slrn_Group_Keymap); SLkm_define_key ("q", (FVOID_STAR) slrn_group_quit, Slrn_Group_Keymap); SLkm_define_key ("^X^C", (FVOID_STAR) slrn_group_quit, Slrn_Group_Keymap); SLkm_define_key ("^X^T", (FVOID_STAR) transpose_groups, Slrn_Group_Keymap); SLkm_define_key ("^R", (FVOID_STAR) slrn_redraw, Slrn_Group_Keymap); SLkm_define_key ("^L", (FVOID_STAR) slrn_redraw, Slrn_Group_Keymap); SLkm_define_key ("^P", (FVOID_STAR) group_up, Slrn_Group_Keymap); #ifdef __os2__ SLkm_define_key ("^@H", (FVOID_STAR) group_up, Slrn_Group_Keymap); SLkm_define_key ("\xE0H", (FVOID_STAR) group_up, Slrn_Group_Keymap); SLkm_define_key ("^@P", (FVOID_STAR) group_down, Slrn_Group_Keymap); SLkm_define_key ("\xE0P", (FVOID_STAR) group_down, Slrn_Group_Keymap); #else SLkm_define_key ("\033[A", (FVOID_STAR) group_up, Slrn_Group_Keymap); SLkm_define_key ("\033OA", (FVOID_STAR) group_up, Slrn_Group_Keymap); SLkm_define_key ("\033[B", (FVOID_STAR) group_down, Slrn_Group_Keymap); SLkm_define_key ("\033OB", (FVOID_STAR) group_down, Slrn_Group_Keymap); #endif SLkm_define_key ("N", (FVOID_STAR) group_down, Slrn_Group_Keymap); SLkm_define_key ("^N", (FVOID_STAR) group_down, Slrn_Group_Keymap); SLkm_define_key ("/", (FVOID_STAR) group_search, Slrn_Group_Keymap); SLkm_define_key ("G", (FVOID_STAR) refresh_groups, Slrn_Group_Keymap); SLkm_define_key ("X", (FVOID_STAR) save_newsrc, Slrn_Group_Keymap); /* mouse (left/right/middle) */ SLkm_define_key ("\033[M\040", (FVOID_STAR) group_mouse_left, Slrn_Group_Keymap); SLkm_define_key ("\033[M\041", (FVOID_STAR) group_mouse_middle, Slrn_Group_Keymap); SLkm_define_key ("\033[M\042", (FVOID_STAR) group_mouse_right, Slrn_Group_Keymap); if (SLang_Error) slrn_exit_error (err); } static void add_group_description (unsigned char *s, unsigned char *smax, unsigned char *dsc) { Slrn_Group_Type *g; unsigned long hash; hash = slrn_compute_hash (s, smax); g = Group_Hash_Table[hash % GROUP_HASH_TABLE_SIZE]; while (g != NULL) { if ((g->hash == hash) && (!strncmp (g->name, (char *) s, (unsigned int) (smax - s)))) { /* Sometimes these get repeated --- not by slrn but on the server! */ if (g->descript != NULL) SLFREE (g->descript); g->descript = (char *) SLMALLOC (strlen ((char *) dsc) + 1); if (g->descript != NULL) { strcpy (g->descript, (char *) dsc); } return; } g = g->hash_next; } } void slrn_get_group_descriptions (void) { FILE *fp; char line[2 * SLRN_MAX_PATH_LEN]; char file[SLRN_MAX_PATH_LEN]; int num; #ifdef VMS sprintf (file, "%s-dsc", Slrn_Newsrc_File); #else # ifdef __os2__ sprintf (file, "ds-%s", Slrn_Newsrc_File); # else sprintf (file, "%s.dsc", Slrn_Newsrc_File); # endif #endif if (NULL == (fp = slrn_open_home_file (file, "w", line, 0))) { slrn_exit_error ("\ Unable to create newsgroup description file:\n%s\n", line); } fprintf (stdout, "Creating description file %s.\n", line); Slrn_Server_Obj->sv_list_newsgroups (); fprintf (stdout, "Getting newsgroup descriptions from server.\n\ Note: This step may take some time if you have a slow connection!!!\n"); fflush (stdout); num = 0; while (NULL != Slrn_Server_Obj->sv_read_line (line, sizeof (line) - 1)) { unsigned char *b, *bmax, *dsc, ch; num = num % 25; if (num == 0) { putc ('.', stdout); fflush (stdout); } /* Check the syntax on this line. They are often corrupt */ b = (unsigned char *) slrn_skip_whitespace (line); bmax = b; while ((ch = *bmax) > ' ') bmax++; if ((ch == 0) || (ch == '\n')) continue; *bmax = 0; /* News group marked off, now get the description. */ dsc = bmax + 1; while (((ch = *dsc) <= ' ') && (ch != 0)) dsc++; if ((ch == 0) || (ch == '?') || (ch == '\n')) continue; /* add_group_description (b, bmax, dsc); */ fputs ((char *) b, fp); putc(':', fp); fputs ((char *) dsc, fp); putc('\n', fp); num++; } slrn_fclose (fp); putc ('\n', stdout); } int slrn_read_group_descriptions (void) { FILE *fp; char line[2 * SLRN_MAX_PATH_LEN]; char file[SLRN_MAX_PATH_LEN]; #ifdef VMS sprintf (file, "%s-dsc", Slrn_Newsrc_File); #else # ifdef __os2__ sprintf (file, "ds-%s", Slrn_Newsrc_File); # else sprintf (file, "%s.dsc", Slrn_Newsrc_File); # endif #endif if (NULL == (fp = slrn_open_home_file (file, "r", line, 0))) { if (Slrn_Lib_Dir != NULL) { #ifdef VMS sprintf (file, "%snewsgroups.dsc", Slrn_Lib_Dir); if (NULL == (fp = slrn_open_home_file (file, "r", line, 0))) { sprintf (file, "%snewsgroups-dsc", Slrn_Lib_Dir); fp = slrn_open_home_file (file, "r", line, 0); } #else sprintf (file, "%s/newsgroups.dsc", Slrn_Lib_Dir); fp = slrn_open_home_file (file, "r", line, 0); #endif } if (fp == NULL) return -1; } while (NULL != fgets (line, sizeof (line) - 1, fp)) { unsigned char *bmax, *dsc, ch; bmax = (unsigned char *) line; while (((ch = *bmax) != ':') && ch) bmax++; if (ch <= ' ') continue; *bmax = 0; dsc = bmax + 1; add_group_description ((unsigned char *) line, bmax, dsc); } slrn_fclose (fp); return 0; } int Slrn_Unsubscribe_New_Groups = 0; void slrn_check_new_groups (int create_flag) { FILE *fp; time_t tloc; struct tm *tm_struct; char line[SLRN_MAX_PATH_LEN]; char file[SLRN_MAX_PATH_LEN]; int num; char *p; int parse_error = 0; #ifdef VMS sprintf (file, "%s-time", Slrn_Newsrc_File); #else #ifdef __os2__ sprintf (file, "tm-%s", Slrn_Newsrc_File); #else sprintf (file, "%s.time", Slrn_Newsrc_File); #endif #endif if ((create_flag == 0) && (NULL != (fp = slrn_open_home_file (file, "r", line, 0)))) { char ch; int i; *line = 0; fgets (line, sizeof (line), fp); slrn_fclose (fp); time (&tloc); parse_error = 1; /* parse this line to make sure it is ok. If it is bad, issue a warning * and go on. */ if (strncmp ("NEWGROUPS ", line, 10)) goto parse_error_label; p = line + 10; p = slrn_skip_whitespace (p); /* parse yymmdd */ for (i = 0; i < 6; i++) { ch = p[i]; if ((ch < '0') || (ch > '9')) goto parse_error_label; } if (p[6] != ' ') goto parse_error_label; ch = p[2]; if (ch > '1') goto parse_error_label; if ((ch == '1') && (p[3] > '2')) goto parse_error_label; ch = p[4]; if (ch > '3') goto parse_error_label; if ((ch == '3') && (p[5] > '1')) goto parse_error_label; /* Now the hour: hhmmss */ p = slrn_skip_whitespace (p + 6); for (i = 0; i < 6; i++) { ch = p[i]; if ((ch < '0') || (ch > '9')) goto parse_error_label; } ch = p[0]; if (ch > '2') goto parse_error_label; if ((ch == '2') && (p[1] > '3')) goto parse_error_label; if ((p[2] > '5') || (p[4] > '5')) goto parse_error_label; p = slrn_skip_whitespace (p + 6); if ((p[0] == 'G') && (p[1] == 'M') && (p[2] == 'T')) p += 3; *p = 0; parse_error = 0; switch (Slrn_Server_Obj->sv_put_server_cmd (line, line, sizeof (line))) { case OK_NEWGROUPS: break; case ERR_FAULT: slrn_message ("Server does not implement NEWGROUPS command."); return; default: slrn_message ("Server failed to return proper response to NEWGROUPS:\n%s\n", line); goto parse_error_label; } num = 0; while (NULL != Slrn_Server_Obj->sv_read_line (line, sizeof (line))) { /* line contains new newsgroup name */ add_unsubscribed_group (line); num++; } if (num) { if (Slrn_TT_Initialized & 1) { slrn_message ("%d new newsgroup(s) found.", num); slrn_smg_refresh (); } else slrn_tty_message (2, "%d new newsgroup(s) found.", num); } } else time (&tloc); parse_error_label: if (parse_error) { slrn_message ("\ %s appears corrupt.\n\ I expected to see see: NEWGROUPS yymmdd hhmmss GMT\n\ I will patch the file up for you.\n", file); } if (NULL == (fp = slrn_open_home_file (file, "w", line, 1))) { slrn_exit_error ("Unable to open %s to record date.", line); } #ifdef VMS tm_struct = localtime (&tloc); fprintf (fp, "NEWGROUPS %02d%02d%02d %02d%02d%02d", tm_struct->tm_year, 1 + tm_struct->tm_mon, tm_struct->tm_mday, tm_struct->tm_hour, tm_struct->tm_min, tm_struct->tm_sec); #else tm_struct = gmtime (&tloc); fprintf (fp, "NEWGROUPS %02d%02d%02d %02d%02d%02d GMT", tm_struct->tm_year, 1 + tm_struct->tm_mon, tm_struct->tm_mday, tm_struct->tm_hour, tm_struct->tm_min, tm_struct->tm_sec); #endif slrn_fclose (fp); } static Slrn_Group_Type *place_group_in_newsrc_order (Slrn_Group_Type *last_group) { Slrn_Group_Type *next_group, *prev_group; next_group = Current_Group->next; prev_group = Current_Group->prev; if (next_group != NULL) next_group->prev = prev_group; if (prev_group != NULL) prev_group->next = next_group; Current_Group->prev = last_group; if (last_group != NULL) { Current_Group->next = last_group->next; if (Current_Group->next != NULL) Current_Group->next->prev = Current_Group; last_group->next = Current_Group; } else if (Current_Group != Groups) { Current_Group->next = Groups; if (Groups != NULL) Groups->prev = Current_Group; Groups = Current_Group; } return Current_Group; } int slrn_read_newsrc (int create_flag) { char file[SLRN_MAX_PATH_LEN]; FILE *fp = NULL; char line[NNTP_BUFFER_SIZE]; register char *p, ch; Line_Num = 0; if (create_flag) { if (NULL == (fp = slrn_open_home_file (Slrn_Newsrc_File, "w", file, 1))) { slrn_exit_error ("Unable to create %s.", file); } fputs ("\n--The next step may take a while if the NNTP connection is slow.--\n\n", stdout); fprintf (stdout, "Creating %s.", file); fflush (stdout); } if (create_flag || Slrn_List_Active_File) { int count = 0; (void) Slrn_Server_Obj->sv_list_active (); while (NULL != Slrn_Server_Obj->sv_read_line (line, sizeof(line))) { unsigned int len; int min, max; parse_active_line (line, &len, &min, &max); if (NULL == create_group_entry (line, len, min, max, 0, 0)) continue; if (create_flag) { count++; count = count % 50; if (count == 0) { putc ('.', stdout); fflush (stdout); } if ((*line == 'n') && (!strncmp (line, "news.newusers.questions", 23) || !strncmp (line, "news.groups.questions", 21) || !strncmp (line, "news.answers", 12) || !strncmp (line, "news.announce.newusers", 22) || !strncmp (line, "news.software.readers", 21))) { add_group (line, len, 0, 1); } else if ((*line == 'a') && (!strncmp (line, "alt.test", 8))) { add_group (line, len, 0, 1); } else add_group (line, len, GROUP_UNSUBSCRIBED, 1); } } } if (create_flag == 0) { Slrn_Group_Type *last_group = NULL; if (Unsubscribed_Groups != NULL) { unsigned int subscribe_flag; Unsubscribed_Slrn_Group_Type *ug = Unsubscribed_Groups, *ugnext; if (Slrn_Unsubscribe_New_Groups) subscribe_flag = GROUP_UNSUBSCRIBED | GROUP_NEW_GROUP_FLAG; else subscribe_flag = GROUP_NEW_GROUP_FLAG; while (ug != NULL) { ugnext = ug->next; if ((-1 != add_group (ug->name, strlen (ug->name), subscribe_flag, 0)) && Slrn_List_Active_File) last_group = place_group_in_newsrc_order (last_group); SLFREE (ug); ug = ugnext; } Unsubscribed_Groups = NULL; } if ((NULL == (fp = slrn_open_home_file (Slrn_Newsrc_File, "r", file, 0))) && (NULL == (fp = slrn_open_home_file (".newsrc", "r", file, 0)))) { sprintf (line, "Unable to open %s.", file); slrn_exit_error (line); } while (fgets (line, sizeof(line) - 1, fp) != NULL) { p = line; while (((ch = *p) != '!') && (ch != ':') && (ch != 0)) { p++; } if ((ch == 0) || (p == line)) continue; if (-1 == add_group (line, (unsigned int) (p - line), ((ch == '!') ? GROUP_UNSUBSCRIBED : 0), 0)) continue; /* perform a re-arrangement to match arrangement in the * newsrc file */ if (Slrn_List_Active_File && (ch != '!')) { last_group = place_group_in_newsrc_order (last_group); } } } slrn_fclose (fp); Current_Group = Groups; find_line_num (); toggle_hide_groups (); /* Unhide the new groups. Do it here so that if there are no unread * articles, it will be visible but also enables user to toggle them * so that they will become invisble again. */ Current_Group = Groups; while ((Current_Group != NULL) && (Current_Group->flags & GROUP_NEW_GROUP_FLAG)) { Current_Group->flags &= ~GROUP_HIDDEN; Current_Group = Current_Group->next; } Current_Group = Groups; find_line_num (); if (create_flag) { /* toggle_list_all_groups1 (0); */ } if (create_flag) Slrn_Groups_Dirty = 1; group_bob (); return 0; } int slrn_select_group_mode (void) { Slrn_Current_Mode = &Group_Mode_Cap; quick_help (); Last_Cursor_Row = 0; Top_Group = NULL; Slrn_Full_Screen_Update = 1; return 0; } /* ----------------------- update screen for group mode ---------- */ static void group_update_screen (void) { Slrn_Group_Type *g; int height = Slrn_Group_Window_Size; int row; int curr_row = 0; /* erase last cursor */ if (Last_Cursor_Row && !Slrn_Full_Screen_Update) { SLsmg_gotorc (Last_Cursor_Row, 0); SLsmg_write_string (" "); } g = Top_Group; /* Find out if the group is already visible */ row = 0; while ((g != NULL) && (g != Current_Group) && (row < height)) { if (g->flags & GROUP_HIDDEN) { while ((g != NULL) && (g->flags & GROUP_HIDDEN)) { g = g->next; } } else { g = g->next; row++; } } if (row == height) g = NULL; Last_Cursor_Row = row + 1; if (g == NULL) { Top_Group = g = Current_Group; Slrn_Full_Screen_Update = 1; } else g = Top_Group; for (row = 0; row < height; row++) { while ((g != NULL) && (g->flags & GROUP_HIDDEN)) g = g->next; if (g == Current_Group) { curr_row = row; } if (g != NULL) { if (Slrn_Full_Screen_Update || (g->flags & GROUP_TOUCHED)) { SLsmg_gotorc (row + 1, 0); SLsmg_printf (" %c%5d ", ((g->flags & GROUP_UNSUBSCRIBED) ? 'U' : ((g->flags & GROUP_NEW_GROUP_FLAG) ? 'N' : ' ')), g->unread); slrn_set_color (GROUP_COLOR); SLsmg_printf ("%s", g->name); slrn_set_color (0); SLsmg_erase_eol (); if (Slrn_Group_Display_Descriptions) { if (g->descript != NULL) { int dsc_row; dsc_row = SLsmg_get_column (); if (dsc_row < Slrn_Group_Description_Column) dsc_row = Slrn_Group_Description_Column; else dsc_row++; SLsmg_gotorc (row + 1, dsc_row); SLsmg_set_color (GROUP_DESCR_COLOR); SLsmg_write_string (g->descript); SLsmg_set_color (0); } } else if (g->range.max != -1) { SLsmg_gotorc (row + 1, 63); SLsmg_printf ("%7d-%-7d", g->range.min, g->range.max); } g->flags &= ~GROUP_TOUCHED; if (g == Current_Group) Last_Cursor_Row = row + 1; } Bottom_Group = g; g = g->next; } else if (Slrn_Full_Screen_Update) { SLsmg_gotorc (row + 1, 0); SLsmg_erase_eol (); Bottom_Group = NULL; } } SLsmg_gotorc (SLtt_Screen_Rows - 2, 0); slrn_set_color (STATUS_COLOR); if (Slrn_Groups_Dirty) SLsmg_write_string ("-*-News Groups: "); else SLsmg_write_string ("---News Groups: "); if (Slrn_Server_Obj->sv_name != NULL) SLsmg_write_string (Slrn_Server_Obj->sv_name); slrn_print_percent (SLtt_Screen_Rows - 2, 60, Line_Num, Num_Groups, height - curr_row); if (Slrn_Use_Mouse) slrn_update_group_menu (); else update_top_status_line (); if (Slrn_Message_Present == 0) quick_help (); SLsmg_gotorc (Last_Cursor_Row, 0); slrn_set_color (CURSOR_COLOR); SLsmg_write_string ("->"); slrn_set_color (0); Slrn_Full_Screen_Update = 0; } char *slrn_current_group (void) { if (Current_Group == NULL) return ""; return Current_Group->name; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.