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