]> andersk Git - moira.git/blob - clients/blanche/blanche.c
add server name to sms_conect call
[moira.git] / clients / blanche / blanche.c
1 /* $Header$
2  *
3  * Command line oriented SMS List tool.
4  *
5  * by Mark Rosenstein, September 1988.
6  *
7  * Copyright 1989 by the Massachusetts Institute of Technology.
8  *
9  * (c) Copyright 1988 by the Massachusetts Institute of Technology.
10  * For copying and distribution information, please see the file
11  * <mit-copyright.h>.
12  */
13
14 /* ### Aren't there a lot of sq abstraction barrier violations here?
15    Do we need to improve the support for queue operations? */
16
17 #include <mit-copyright.h>
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <sms.h>
21 #include <sms_app.h>
22
23 #ifndef LINT
24 static char smslist_rcsid[] = "$Header$";
25 #endif
26
27
28 struct member {
29     int type;
30     char *name;
31 };
32
33 /* It is important to membercmp that M_USER < M_LIST < M_STRING */
34 #define M_ANY           0
35 #define M_USER          1
36 #define M_LIST          2
37 #define M_STRING        3
38
39 /* argument parsing macro */
40 #define argis(a,b) ((strcmp(*arg+1, a) == 0) || (strcmp(*arg+1, b) == 0))
41
42 /* flags from command line */
43 int infoflg, verbose, syncflg, memberflg, recursflg, debugflg;
44
45 /* various member lists */
46 struct save_queue *addlist, *dellist, *memberlist, *synclist;
47
48 char *listname, *whoami;
49
50 extern char *index();
51 extern int errno;
52
53 int show_list_info(), show_list_count(), get_list_members(), scream();
54 int show_list_members();
55 struct member *parse_member();
56
57
58
59 main(argc, argv)
60 int argc;
61 char **argv;
62 {
63     int status;
64     char **arg = argv;
65     char *membervec[3];
66     struct member *memberstruct;
67
68     /* clear all flags & lists */
69     infoflg = verbose = syncflg = memberflg = debugflg = recursflg = 0;
70     listname = NULL;
71     addlist = sq_create();
72     dellist = sq_create();
73     memberlist = sq_create();
74     synclist = sq_create();
75     whoami = argv[0];
76
77     /* parse args, building addlist, dellist, & synclist */
78     while (++arg - argv < argc) {
79         if  (**arg == '-')
80         {
81             if (argis("m", "members"))
82                 memberflg++;
83             else if (argis("D", "debug"))
84                 debugflg++;
85             else if (argis("i","information"))
86               infoflg++;
87             else if (argis("v","verbose"))
88               verbose++;
89             else if (argis("r","recursive"))
90               recursflg++;
91             else if (argis("a","add"))
92                 if (arg - argv < argc - 1) {
93                     ++arg;
94                     if (memberstruct = parse_member(*arg))
95                         sq_save_data(addlist, memberstruct);
96                 } else
97                     usage(argv);
98             else if (argis("d","delete"))
99                 if (arg - argv < argc - 1) {
100                     ++arg;
101                     if (memberstruct = parse_member(*arg))
102                         sq_save_data(dellist, memberstruct);
103                 } else
104                     usage(argv);
105             else if (argis("f","file"))
106                 if (arg - argv < argc - 1) {
107                     FILE *in;
108                     char buf[BUFSIZ];
109
110                     syncflg++;
111                     ++arg;
112                     if (!strcmp(*arg, "-"))
113                       in = stdin;
114                     else {
115                         in = fopen(*arg, "r");
116                         if (!in) {
117                             com_err(whoami, errno, 
118                                     " while opening %s for input", *arg);
119                             exit(2);
120                         }
121                     }
122                     while (fgets(buf, BUFSIZ, in))
123                       if (memberstruct = parse_member(buf))
124                         sq_save_data(synclist, memberstruct);
125                     if (!feof(in))
126                       com_err(whoami, errno, " while reading from %s", *arg);
127                 } else
128                   usage(argv);
129             else
130                 usage(argv);
131         }
132         else if (listname == NULL)
133           listname = *arg;
134         else
135           usage(argv);
136     }
137     if (listname == NULL)
138       usage(argv);
139
140     /* if no other options specified, turn on list members flag */
141     if (!(infoflg || syncflg ||
142           addlist->q_next != addlist || dellist->q_next != dellist))
143       memberflg++;
144
145     /* fire up SMS */
146     if (status = sms_connect(SMS_SERVER)) {
147         com_err(whoami, status, " unable to connect to SMS");
148         exit(2);
149     }
150     if (status = sms_auth("blanche")) {
151         com_err(whoami, status, " unable to authenticate to SMS");
152         exit(2);
153     }
154
155     /* display list info if requested to */
156     if (infoflg) {
157         status = sms_query("get_list_info", 1, &listname, show_list_info,NULL);
158         if (status)
159           com_err(whoami, status, " while getting list information");
160         if (verbose && !memberflg) {
161             status = sms_query("count_members_of_list", 1, &listname,
162                                show_list_count, NULL);
163             if (status)
164               com_err(whoami, status, " while getting list count");
165         }
166     }
167
168     /* if we're synchronizing to a file, we need to:
169      *  get the current members of the list
170      *  for each member of the sync file
171      *     if they are on the list, remove them from the in-memory copy
172      *     if they're not on the list, add them to add-list
173      *  if anyone is left on the in-memory copy, put them on the delete-list
174      * lastly, reset memberlist so we can use it again later
175      */
176     if (syncflg) {
177         status = sms_query("get_members_of_list", 1, &listname,
178                            get_list_members, (char *)memberlist);
179         if (status)
180           com_err(whoami, status, " getting members of list %s", listname);
181         while (sq_get_data(synclist, &memberstruct)) {
182             struct save_queue *q;
183             int removed = 0;
184
185             for (q = memberlist->q_next; q != memberlist; q = q->q_next) {
186                 if (membercmp(q->q_data, memberstruct) == 0) {
187                     q->q_prev->q_next = q->q_next;
188                     q->q_next->q_prev = q->q_prev;
189                     removed++;
190                     break;
191                 }
192             }
193             if (!removed)
194               sq_save_data(addlist, memberstruct);
195         }
196         while (sq_get_data(memberlist, &memberstruct))
197           sq_save_data(dellist, memberstruct);
198         sq_destroy(memberlist);
199         memberlist = sq_create();
200     }
201
202     /* Process the add list */
203     while (sq_get_data(addlist, &memberstruct)) {
204         membervec[0] = listname;
205         membervec[2] = memberstruct->name;
206         if (verbose && syncflg) {
207             printf("Adding member ");
208             show_list_member(memberstruct);
209         }
210         switch (memberstruct->type) {
211         case M_ANY:
212         case M_USER:
213             membervec[1] = "USER";
214             status = sms_query("add_member_to_list", 3, membervec, scream, NULL);
215             if (status == SMS_SUCCESS)
216               break;
217             else if (status != SMS_USER || memberstruct->type != M_ANY) {
218                 com_err(whoami, status, " while adding member %s to %s",
219                         memberstruct->name, listname);
220                 break;
221             }
222         case M_LIST:
223             membervec[1] = "LIST";
224             status = sms_query("add_member_to_list", 3, membervec,
225                                scream, NULL);
226             if (status == SMS_SUCCESS)
227               break;
228             else if (status != SMS_LIST || memberstruct->type != M_ANY) {
229                 com_err(whoami, status, " while adding member %s to %s",
230                         memberstruct->name, listname);
231                 break;
232             }
233         case M_STRING:
234             membervec[1] = "STRING";
235             status = sms_query("add_member_to_list", 3, membervec,
236                                scream, NULL);
237             if (status != SMS_SUCCESS)
238               com_err(whoami, status, " while adding member %s to %s",
239                       memberstruct->name, listname);
240         }
241     }
242
243     /* Process the delete list */
244     while (sq_get_data(dellist, &memberstruct)) {
245         membervec[0] = listname;
246         membervec[2] = memberstruct->name;
247         if (verbose && syncflg) {
248             printf("Deleting member ");
249             show_list_member(memberstruct);
250         }
251         switch (memberstruct->type) {
252         case M_ANY:
253         case M_USER:
254             membervec[1] = "USER";
255             status = sms_query("delete_member_from_list", 3, membervec,
256                                scream, NULL);
257             if (status == SMS_SUCCESS)
258               break;
259             else if ((status != SMS_USER && status != SMS_NO_MATCH) ||
260                      memberstruct->type != M_ANY) {
261                 com_err(whoami, status, " while deleteing member %s from %s",
262                         memberstruct->name, listname);
263                 break;
264             }
265         case M_LIST:
266             membervec[1] = "LIST";
267             status = sms_query("delete_member_from_list", 3, membervec,
268                                scream, NULL);
269             if (status == SMS_SUCCESS)
270               break;
271             else if ((status != SMS_LIST && status != SMS_NO_MATCH) ||
272                      memberstruct->type != M_ANY) {
273                 com_err(whoami, status, " while deleteing member %s from %s",
274                         memberstruct->name, listname);
275                 break;
276             }
277         case M_STRING:
278             membervec[1] = "STRING";
279             status = sms_query("delete_member_from_list", 3, membervec,
280                                scream, NULL);
281             if (status == SMS_STRING && memberstruct->type == M_ANY)
282               com_err(whoami, 0, "Unable to find member %s to delete from %s",
283                       memberstruct->name, listname);
284             else if (status != SMS_SUCCESS)
285               com_err(whoami, status, " while deleteing member %s from %s",
286                       memberstruct->name, listname);
287         }
288     }
289
290     /* Display the members of the list now, if requested */
291     if (memberflg) {
292         if (recursflg)
293           recursive_display_list_members();
294         else {
295             status = sms_query("get_members_of_list", 1, &listname,
296                                get_list_members, (char *)memberlist);
297             if (status)
298               com_err(whoami, status, " while getting members of list %s",
299                       listname);
300             while (sq_get_data(memberlist, &memberstruct))
301               show_list_member(memberstruct);
302         }
303     }
304
305     /* We're done! */
306     sms_disconnect();
307     exit(0);
308 }
309
310 usage(argv)
311 char **argv;
312 {
313     fprintf(stderr, "Usage: %s [options] listname [options]\n",argv[0]);
314     fprintf(stderr, "Options are\n");
315     fprintf(stderr, "   -v | -verbose\n");
316     fprintf(stderr, "   -m | -members\n");
317     fprintf(stderr, "   -i | -info\n");
318     fprintf(stderr, "   -r | -recursive\n");
319     fprintf(stderr, "   -a | -add member\n");
320     fprintf(stderr, "   -d | -delete member\n");
321     fprintf(stderr, "   -f | -file filename\n");
322     fprintf(stderr, "   -D | -debug\n");
323     exit(1);
324 }
325
326
327 /* Display the members stored in the queue */
328
329 show_list_member(memberstruct)
330 struct member *memberstruct;
331 {
332     if (verbose) {
333         char *s;
334         switch (memberstruct->type) {
335         case M_USER:
336             s = "USER";
337             break;
338         case M_LIST:
339             s = "LIST";
340             break;
341         case M_STRING:
342             s = "STRING";
343             break;
344         case M_ANY:
345             printf("%s\n", memberstruct->name);
346             return;
347         }
348         printf("%s:%s\n", s, memberstruct->name);
349     } else {
350         if (memberstruct->type == M_LIST)
351           printf("LIST:%s\n", memberstruct->name);
352         else if (memberstruct->type == M_STRING &&
353                  !index(memberstruct->name, '@'))
354           printf("STRING:%s\n", memberstruct->name);
355         else
356           printf("%s\n", memberstruct->name);
357     }
358 }
359
360
361 /* Show the retrieved information about a list */
362
363 show_list_info(argc, argv, hint)
364 int argc;
365 char **argv;
366 int hint;
367 {
368     printf("List: %s\n", argv[0]);
369     printf("Description: %s\n", argv[9]);
370     printf("Flags: %s, %s, and %s\n",
371            atoi(argv[1]) ? "active" : "inactive",
372            atoi(argv[2]) ? "public" : "private",
373            atoi(argv[3]) ? "hidden" : "visible");
374     printf("%s is %sa maillist and is %sa group", argv[0],
375            atoi(argv[4]) ? "" : "not ",
376            atoi(argv[5]) ? "" : "not ");
377     if (atoi(argv[5]))
378       printf(" with GID %d\n", atoi(argv[6]));
379     else
380       printf("\n");
381     printf("Owner: %s %s\n", argv[7], argv[8]);
382     printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
383     return(SMS_CONT);
384 }
385
386
387 /* Show the retrieve list member count */
388
389 show_list_count(argc, argv, hint)
390 int argc;
391 char **argv;
392 int hint;
393 {
394     printf("Members: %s\n", argv[0]);
395 }
396
397
398 /* Recursively find all of the members of listname, and then display them */
399
400 recursive_display_list_members()
401 {
402     int status, count, savecount;
403     struct save_queue *lists, *members;
404     struct member *m, *m1, *data;
405
406     lists = sq_create();
407     members = sq_create();
408     m = (struct member *) malloc(sizeof(struct member));
409     m->type = M_LIST;
410     m->name = listname;
411     sq_save_data(lists, m);
412
413     while (sq_get_data(lists, &m)) {
414         sq_destroy(memberlist);
415         memberlist = sq_create();
416         if (debugflg)
417           fprintf(stderr, "Fetching members of %s\n", m->name);
418         status = sms_query("get_members_of_list", 1, &(m->name),
419                            get_list_members, (char *)memberlist);
420         if (status)
421           com_err(whoami, status, " while getting members of list %s", m->name);
422         while (sq_get_data(memberlist, &m1)) {
423             if (m1->type == M_LIST)
424               unique_add_member(lists, m1);
425             else
426               unique_add_member(members, m1);
427         }
428     }
429     savecount = count = sq_count_elts(members);
430     data = (struct member *) malloc(count * sizeof(struct member));
431     count = 0;
432     while (sq_get_data(members, &m))
433       bcopy(m, &data[count++], sizeof(struct member));
434     qsort(data, count, sizeof(struct member), membercmp);
435     for (count = 0; count < savecount; count++) {
436         show_list_member(&data[count]);
437     }
438 }
439
440
441 /* add a struct member to a queue if that member isn't already there. */
442
443 unique_add_member(q, m)
444 struct save_queue  *q;
445 struct member *m;
446 {
447     struct save_queue *qp;
448
449     for (qp = q->q_next; qp != q; qp = qp->q_next) {
450         if (!membercmp(qp->q_data, m))
451           return;
452     }
453     sq_save_data(q, m);
454 }
455
456
457 /* Collect the retrieved members of the list */
458
459 get_list_members(argc, argv, q)
460 int argc;
461 char **argv;
462 struct save_queue *q;
463 {
464     struct member *m;
465
466     m = (struct member *) malloc(sizeof(struct member));
467     switch (argv[0][0]) {
468     case 'U':
469         m->type = M_USER;
470         break;
471     case 'L':
472         m->type = M_LIST;
473         break;
474     case 'S':
475         m->type = M_STRING;
476         break;
477     }
478     m->name = strsave(argv[1]);
479     sq_save_data(q, m);
480     return(SMS_CONT);
481 }
482
483
484 /* Called only if a query returns a value that we weren't expecting */
485
486 scream()
487 {
488     fprintf(stderr, "Programmer botch\n");
489     exit(3);
490 }
491
492
493 /* Parse a line of input, fetching a member.  NULL is returned if a member
494  * is not found.  Only the first token on the line is parsed.  ';' is a
495  * comment character.
496  */
497
498 struct member *parse_member(s)
499 register char *s;
500 {
501     register struct member *m;
502     char *p;
503
504     while (*s && isspace(*s))
505       s++;
506     p = s;
507     while (*p && isprint(*p) && !isspace(*p) && *p != ';')
508       p++;
509     *p = 0;
510     if (p == s || strlen(s) == 0)
511       return(NULL);
512
513     if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
514       return(NULL);
515
516     if (p = index(s, ':')) {
517         *p = 0;
518         m->name = ++p;
519         if (!strcasecmp("user", s))
520           m->type = M_USER;
521         else if (!strcasecmp("list", s))
522           m->type = M_LIST;
523         else if (!strcasecmp("string", s))
524           m->type = M_STRING;
525         else {
526             m->type = M_STRING;
527             *(--p) = ':';
528             m->name = s;
529         }
530         m->name = strsave(m->name);
531         return(m);
532     }
533     m->name = strsave(s);
534     if (index(s, '@') || index(s, '!') || index(s, '%'))
535       m->type = M_STRING;
536     else
537       m->type = M_ANY;
538     return(m);
539 }
540
541
542   /* 
543    * This routine two compares members by the following rules:
544    * 1.  A USER is less than a LIST
545    * 2.  A LIST is less than a STRING
546    * 3.  If two members are of the same type, the one alphabetically first
547    *     is less than the other
548    * It returs < 0 if the first member is less, 0 if they are identical, and
549    * > 0 if the second member is less (the first member is greater).
550    */
551
552 int membercmp(m1, m2)
553   struct member *m1, *m2;
554 {
555     if (m1->type == M_ANY || m2->type  == M_ANY || (m1->type == m2->type))
556         return(strcmp(m1->name, m2->name));
557     else
558         return(m1->type - m2->type);
559 }
560
561
562 sq_count_elts(q)
563 struct save_queue *q;
564 {
565     char  *foo;
566     int count;
567
568     count = 0;
569     while (sq_get_data(q, &foo))
570       count++;
571     return(count);
572 }
This page took 0.104614 seconds and 5 git commands to generate.