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