]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/clients/xzwrite/destlist.c
finalize -3
[1ts-debian.git] / zephyr / clients / xzwrite / destlist.c
1 #include <sysdep.h>
2 #include <dyn.h>
3
4 #include "xzwrite.h"
5
6 /*
7  * The following code extracts keypressed from an X event:
8  * 
9  * keyevent = event->xkey;
10  * XLookupString(&keyevent, buffer, 1, NULL, NULL);
11  */
12
13 /*
14  * This entire file could easily be changes so that multiple destination
15  * lists could be used.  But I don't know that that's necessary for this
16  * program.
17  */
18
19 /* Globals */
20 DestRec current_dest;
21
22 static DynObject        dests;
23 extern Defaults         defs;
24
25 static void get_dest_from_file(), _get_default_dest();
26 static int sort_dest_func(const void *, const void *);
27
28 /* A function for debugging */
29 void dest_print()
30 {
31      char **d;
32      int i;
33
34      d = (char **) DynGet(dests, 0);
35      for (i=0; i<DynSize(dests); i++)
36           printf("%d %s\n", i, d[i]);
37 }
38
39 char **dest_text()
40 {
41      return ((char **) DynGet(dests, 0));
42 }
43
44 int dest_num()
45 {
46      return (DynSize(dests));
47 }
48
49 void dest_set_current_dest(dest)
50    Dest       dest;
51 {
52      (void) memcpy((char *) &current_dest, (char *) dest, sizeof(DestRec));
53 }
54
55 void dest_init()
56 {
57      dests = DynCreate(sizeof(char *), 0);
58      if (! dests)
59           Error("Out of memory reading destinations", NULL);
60
61      strcpy(current_dest.zclass, DEFAULT_CLASS);
62      strcpy(current_dest.zinst, DEFAULT_INST);
63      strcpy(current_dest.zrecip, get_username());
64 }
65
66 char **load_default_dest()
67 {
68      char       *get_home_dir();
69
70      if (! *get_home_dir())
71           Error("Cannot find your home directory.", NULL);
72
73      if (defs.read_xzwrite)
74           _get_default_dest(XZWRITE_DEST_FILE);
75      if (defs.read_zephyr)
76           _get_default_dest(ZEPHYR_FILE);
77      if (defs.read_anyone)
78           _get_default_dest(ANYONE_FILE);
79
80      if (DynSize(dests) == 0) {
81           char *def;
82           
83           Warning("XZwrite: No destinations specified, using default.",
84                   NULL);
85
86           def = (char *) Malloc(strlen("...") + 1, "adding default dests",
87                                 NULL);
88           strcpy(def, "...");
89           if (DynAdd(dests, (char *) &def) == DYN_NOMEM)
90                Error("Out of memory adding default destinations.", NULL);
91      }
92
93      sort_destinations();
94      return ((char **) DynGet(dests, 0));
95 }
96
97 static void _get_default_dest(s)
98    char *s;
99 {
100      char       *filename;
101      
102      filename = (char *) Malloc(strlen(get_home_dir()) + strlen(s) + 1,
103                                 "While reading file ", s, NULL);
104      sprintf(filename, "%s%s", get_home_dir(), s);
105      get_dest_from_file(dests, filename);
106      free(filename);
107 }
108
109 static void get_dest_from_file(dests, f)
110    DynObject    dests;
111    char         *f;
112 {
113      FILE       *file;
114      char       *line, buf[BUFSIZ];
115      DestRec    dest;
116
117      if ((file = fopen(f, "r")) == NULL) {
118           Warning("Cannot find destinations file ", f, NULL);
119           return;
120      }
121      
122      while (bfgets(buf, 80, file)) {
123           if (buf[0] == '#' || buf[0] == '\0') {
124                if (defs.debug)
125                     printf("xzwrite: skipping comment or blank line\n");
126                continue;
127           }
128           
129           if (! parse_into_dest(&dest, buf)) {
130                Warning("Ignoring incorrect destination: ", buf, NULL);
131                continue;
132           }
133
134           line = (char *) Malloc(strlen(buf) + 1, "parsing file ", f, NULL);
135           strcpy(line, buf);
136           if (DynAdd(dests, (char *) &line) == DYN_NOMEM)
137                Error("Out of memory parsing file ", f, NULL);
138      }
139      
140      fclose(file);
141 }
142
143 char **dest_add(dest)
144    Dest dest;
145 {
146      char *buf;
147
148      /* Two extra bytes if instance or recipient are "" */
149      buf = (char *) Malloc(strlen(dest->zclass) + strlen(dest->zinst) +
150                            strlen(dest->zrecip) + 5,
151                            "while adding destination ", NULL);
152      sprintf(buf, "%s,%s,%s", dest->zclass,
153              *dest->zinst ? dest->zinst : "*",
154              *dest->zrecip ? dest->zrecip : "*");
155
156      if (DynAdd(dests, (DynPtr) &buf) == DYN_NOMEM) {
157           Warning("Out of memory adding destination ", buf, ".  Skipping.",
158                   NULL);
159           free(buf);
160      }
161
162      sort_destinations();
163      return ((char **) DynGet(dests, 0));
164 }
165
166 /* XXX The return/output semantics of this function are not good */
167 char **dest_add_string(s)
168    char *s;
169 {
170      DestRec    dest;
171      
172      if (! parse_into_dest(&dest, s))
173           return NULL;
174      
175      if (DynAdd(dests, (DynPtr) &s) == DYN_NOMEM)
176           Warning("Out of memory adding destination ", s, ".  Skipping.",
177                   NULL);
178
179      sort_destinations();
180      return ((char **) DynGet(dests, 0));
181 }
182
183 char **dest_delete_string(s)
184    char *s;
185 {
186      int        i;
187      char       **d;
188
189      d = (char **) DynGet(dests, 0);
190      for (i=0; i<DynSize(dests); i++) {
191           if (! strcmp(s, d[i])) {
192                DynDelete(dests, i);
193                break;
194           }
195      }
196
197      return ((char **) DynGet(dests, 0));
198 }
199
200 char **delete_dest_index(i)
201    int i;
202 {
203      int        ret;
204
205      ret = DynDelete(dests, i);
206      if (ret != DYN_OK)
207           return NULL;
208
209      return ((char **) DynGet(dests, 0));
210 }
211
212      
213 static int sort_dest_func(a1, a2)
214    const void *a1, *a2;
215 {
216      char       **c1 = (char **) a1, **c2 = (char **) a2;
217      char       *s1, *s2, *i1, *i2;
218
219      /* A string with a , in it is always less than one without */
220      s1 = *c1; s2 = *c2;
221      i1 = strchr(s1, ',');
222      i2 = strchr(s2, ',');
223      if (i1 == NULL && i2 != NULL)
224           return 1;
225      else if (i1 != NULL && i2 == NULL)
226           return -1;
227      else
228           return strcmp(s1, s2);
229 }
230
231 static int
232 binary_find_dest(key)
233 char *key;
234 {
235     register int low = 0, high = DynHigh(dests), mid;
236     register int val;
237     register char **d;
238
239     d = (char **) DynGet(dests, 0);
240
241     /* do binary search */
242     while (low <= high) {
243         mid = (low + high) / 2;
244         val = sort_dest_func(&key, &d[mid]);
245         if (val < 0) {
246             high = mid - 1;
247         } else if (val > 0) {
248             low = mid + 1;
249         } else {
250             return (mid);
251         }
252     }
253
254     return -1;
255 }
256
257 char **sort_destinations()
258 {
259      register char **d;
260      register int idx, idx2;
261      int dsiz = DynSize(dests);
262
263      d = (char **) DynGet(dests, 0);
264      qsort(d, dsiz, sizeof(char *), sort_dest_func);
265      
266      for (idx = 0; idx < DynSize(dests);) {
267         if (d[idx][0] == '!') {
268             /* unsubscription */
269             char *next = d[idx];
270             next++;
271             while ((idx2 = binary_find_dest(next)) >= 0) {
272                 /* found one to nuke */
273                 DynDelete(dests, idx2);
274                 if (idx2 <= idx) {
275                     /* indexes shifted, so restart this pass. */
276                     idx--;
277                     if (idx <= 0)
278                         idx = 0;
279                     continue;
280                 }
281             }
282             /* ok, no more to nuke from this one, so delete it and
283                move on. */
284             DynDelete(dests, idx);
285             continue;
286         }
287         /* nope, continue on to next unsub */
288         idx++;
289      }
290      return d;
291 }
292
293 /* Fills in dest from s */
294 int parse_into_dest(dest, s)
295    Dest dest;
296    char *s;
297 {
298      char       *a, *b;
299      int        x, y;
300
301      /* Check for just recipient */
302      if ((a=strchr(s, ','))==0) {
303           if (strlen(s) > ZLEN)
304                return 0;
305           strcpy(dest->zclass, DEFAULT_CLASS);
306           strcpy(dest->zinst, DEFAULT_INST);
307           strcpy(dest->zrecip, s);
308      }
309
310      /* Check for just class,instance or instace,recipient */
311      else if ((b=strchr((++a), ','))==0) {
312           if (defs.class_inst) {
313                x = a - 1 - s;
314                if (x >= ZLEN)
315                     return 0;
316
317                strncpy(dest->zclass, s, x);
318                dest->zclass[x] = '\0';
319                strcpy(dest->zinst, a);
320                strcpy(dest->zrecip, "*"); }
321           else {
322                x = a - 1 - s;
323                if (x >= ZLEN)
324                     return 0;
325                
326                strcpy(dest->zclass, DEFAULT_CLASS);
327                strncpy(dest->zinst, s, x);
328                dest->zinst[x] = '\0';
329                strcpy(dest->zrecip, a); }
330      }
331
332      /* Otherwise, deal with class,instance,recipent */
333      else {
334           ++b;
335           x = a - 1 - s;
336           y = b - 1 - a;
337           if (x >= ZLEN || y >= ZLEN)
338                return 0;
339           
340           strncpy(dest->zclass, s, x);
341           dest->zclass[x] = '\0';
342           strncpy(dest->zinst, a, y);
343           dest->zinst[y] = '\0';
344           strcpy(dest->zrecip, b);
345      }
346      if (!strcmp(dest->zrecip,"*")) *(dest->zrecip) = '\0';
347      if (!strcmp(dest->zinst,"*")) *(dest->zinst) = '\0';
348
349      return 1;
350 }
351
352 /*
353  * notice is from <MESSAGE,inst,sender>.  If inst is "PERSONAL", add
354  * destination string "<sender>" if
355  *      1) MESSAGE,PERSONAL,<sender> is not in list, and
356  *      2) <sender> is not in list.
357  * If inst is not "PERSONAL", add destination string
358  * "<MESSAGE,<inst>,<sender>>" if it is not in the list.
359  */
360 void dest_add_reply(notice)
361    ZNotice_t *notice;
362 {
363      char **list, *newdest, buf[ZLEN*3+2];
364      int i, num;
365
366      list = dest_text();
367      num = dest_num();
368
369           
370      /* A hack so local-realm is less annoying */
371      {
372           char *r;
373
374           r = strchr(notice->z_sender, '@');
375           if (r && ! strcmp(r+1, ZGetRealm()))
376                *r = '\0';
377      }
378      
379      if (! strcasecmp(notice->z_class_inst, DEFAULT_INST)) {
380           sprintf(buf, "message,personal,%s", notice->z_sender);
381           for (i=0; i < num; i++) {
382                if (! strcasecmp(list[i], buf) ||
383                    ! strcasecmp(list[i], notice->z_sender))
384                     return;
385           }
386
387           newdest = (char *) Malloc(strlen(notice->z_sender) + 1,
388                                 "while adding reply destination", NULL);
389           sprintf(newdest, "%s", notice->z_sender);
390      }
391      else {
392           sprintf(buf, "message,%s,%s", notice->z_class_inst,
393                   notice->z_sender);
394           for (i=0; i < num; i++) {
395                if (! strcasecmp(list[i], buf))
396                     return;
397           }
398
399           newdest = (char *) Malloc(strlen(notice->z_class) +
400                                     strlen(notice->z_class_inst) +
401                                     strlen(notice->z_sender) + 3,
402                                     "while adding reply destintion",
403                                     NULL);
404           sprintf(newdest, "%s,%s,%s", notice->z_class,
405                   notice->z_class_inst, notice->z_sender);
406      }
407
408      dest_add_string(newdest);
409      display_dest();
410
411      if (defs.track_logins)
412           zeph_subto_logins(&notice->z_sender, 1);
413 }
414