]> andersk Git - moira.git/blob - clients/blanche/blanche.c
Added support for verbose commandline options, changed usage message,
[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 /* member types: ### This should be an enumerated type ?
34    It is important to membercmp that M_USER < M_LIST < M_STRING */
35 #define M_ANY           0
36 #define M_USER          1
37 #define M_LIST          2
38 #define M_STRING        3
39
40 /* argument parsing macro */
41 #define argis(a,b) ((strcmp(*arg+1, a) == 0) || (strcmp(*arg+1, b) == 0))
42
43 /* flags from command line */
44 int infoflg, verbose, syncflg, memberflg, recursflg, debugflg;
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     listname = NULL;
72     addlist = sq_create();
73     dellist = sq_create();
74     memberlist = sq_create();
75     synclist = sq_create();
76     whoami = argv[0];
77
78     /* parse args, building addlist, dellist, & synclist */
79     while (++arg - argv < argc) {
80         if  (**arg == '-')
81         {
82             if (argis("m", "members"))
83                 memberflg++;
84             else if (argis("D", "debug"))
85                 debugflg++;
86             else if (argis("i","information"))
87               infoflg++;
88             else if (argis("v","verbose"))
89               verbose++;
90             else if (argis("r","recursive"))
91               recursflg++;
92             else if (argis("a","add"))
93                 if (arg - argv < argc - 1) {
94                     ++arg;
95                     if (memberstruct = parse_member(*arg))
96                         sq_save_data(addlist, memberstruct);
97                 } else
98                     usage(argv);
99             else if (argis("d","delete"))
100                 if (arg - argv < argc - 1) {
101                     ++arg;
102                     if (memberstruct = parse_member(*arg))
103                         sq_save_data(dellist, memberstruct);
104                 } else
105                     usage(argv);
106             else if (argis("f","file"))
107                 if (arg - argv < argc - 1) {
108                     FILE *in;
109                     char buf[BUFSIZ];
110                     
111                     syncflg++;
112                     ++arg;
113                     if (!strcmp(*arg, "-"))
114                         in = stdin;
115                     else {
116                         in = fopen(*arg, "r");
117                 if (!in) {
118                             com_err(whoami, errno, 
119                                     " while opening %s for input", *arg);
120                             exit(2);
121                         }
122                     }
123                     while (fgets(buf, BUFSIZ, in))
124                         if (memberstruct = parse_member(buf))
125                             sq_save_data(synclist, memberstruct);
126                     if (!feof(in))
127                         com_err(whoami, errno, " while reading from %s", *arg);
128                 } else
129                     usage(argv);
130             else
131                 usage(argv);
132         }
133         else if (listname == NULL)
134           listname = *arg;
135         else
136           usage(argv);
137     }
138     if (listname == NULL)
139       usage(argv);
140
141     /* if no other options specified, turn on list members flag */
142     if (!(infoflg || syncflg ||
143           addlist->q_next != addlist || dellist->q_next != dellist))
144       memberflg++;
145
146     /* fire up SMS */
147     if (status = sms_connect()) {
148         com_err(whoami, status, " unable to connect to SMS");
149         exit(2);
150     }
151     if (status = sms_auth("blanche")) {
152         com_err(whoami, status, " unable to authenticate to SMS");
153         exit(2);
154     }
155
156     /* display list info if requested to */
157     if (infoflg) {
158         status = sms_query("get_list_info", 1, &listname, show_list_info,NULL);
159         if (status)
160           com_err(whoami, status, " while getting list information");
161         if (verbose && !memberflg) {
162             status = sms_query("count_members_of_list", 1, &listname,
163                                show_list_count, NULL);
164             if (status)
165               com_err(whoami, status, " while getting list count");
166         }
167     }
168
169     /* if we're synchronizing to a file, we need to:
170      *  get the current members of the list
171      *  for each member of the sync file
172      *     if they are on the list, remove them from the in-memory copy
173      *     if they're not on the list, add them to add-list
174      *  if anyone is left on the in-memory copy, put them on the delete-list
175      * lastly, reset memberlist so we can use it again later
176      */
177     if (syncflg) {
178         status = sms_query("get_members_of_list", 1, &listname,
179                            get_list_members, (char *)memberlist);
180         if (status)
181           com_err(whoami, status, " while getting members of list");
182         while (sq_get_data(synclist, &memberstruct)) {
183             struct save_queue *q;
184             int removed = 0;
185
186             for (q = memberlist->q_next; q != memberlist; q = q->q_next) {
187                 if (membercmp(q->q_data, memberstruct) == 0) {
188                     q->q_prev->q_next = q->q_next;
189                     q->q_next->q_prev = q->q_prev;
190                     removed++;
191                     break;
192                 }
193             }
194             if (!removed)
195               sq_save_data(addlist, memberstruct);
196         }
197         while (sq_get_data(memberlist, &memberstruct))
198           sq_save_data(dellist, memberstruct);
199         sq_destroy(memberlist);
200         memberlist = sq_create();
201     }
202
203     /* Process the add list */
204     while (sq_get_data(addlist, &memberstruct)) {
205         membervec[0] = listname;
206         membervec[2] = memberstruct->name;
207         switch (memberstruct->type) {
208         case M_ANY:
209         case M_USER:
210             membervec[1] = "USER";
211             status = sms_query("add_member_to_list", 3, membervec, scream, NULL);
212             if (status == SMS_SUCCESS)
213               break;
214             else if (status != SMS_USER || memberstruct->type != M_ANY) {
215                 com_err(whoami, status, " while adding member %s to %s",
216                         memberstruct->name, listname);
217                 break;
218             }
219         case M_LIST:
220             membervec[1] = "LIST";
221             status = sms_query("add_member_to_list", 3, membervec,
222                                scream, NULL);
223             if (status == SMS_SUCCESS)
224               break;
225             else if (status != SMS_LIST || memberstruct->type != M_ANY) {
226                 com_err(whoami, status, " while adding member %s to %s",
227                         memberstruct->name, listname);
228                 break;
229             }
230         case M_STRING:
231             membervec[1] = "STRING";
232             status = sms_query("add_member_to_list", 3, membervec,
233                                scream, NULL);
234             if (status != SMS_SUCCESS)
235               com_err(whoami, status, " while adding member %s to %s",
236                       memberstruct->name, listname);
237         }
238     }
239
240     /* Process the delete list */
241     while (sq_get_data(dellist, &memberstruct)) {
242         membervec[0] = listname;
243         membervec[2] = memberstruct->name;
244         switch (memberstruct->type) {
245         case M_ANY:
246         case M_USER:
247             membervec[1] = "USER";
248             status = sms_query("delete_member_from_list", 3, membervec,
249                                scream, NULL);
250             if (status == SMS_SUCCESS)
251               break;
252             else if ((status != SMS_USER && status != SMS_NO_MATCH) ||
253                      memberstruct->type != M_ANY) {
254                 com_err(whoami, status, " while deleteing member %s from %s",
255                         memberstruct->name, listname);
256                 break;
257             }
258         case M_LIST:
259             membervec[1] = "LIST";
260             status = sms_query("delete_member_from_list", 3, membervec,
261                                scream, NULL);
262             if (status == SMS_SUCCESS)
263               break;
264             else if ((status != SMS_LIST && status != SMS_NO_MATCH) ||
265                      memberstruct->type != M_ANY) {
266                 com_err(whoami, status, " while deleteing member %s from %s",
267                         memberstruct->name, listname);
268                 break;
269             }
270         case M_STRING:
271             membervec[1] = "STRING";
272             status = sms_query("delete_member_from_list", 3, membervec,
273                                scream, NULL);
274             if (status == SMS_STRING && memberstruct->type == M_ANY)
275               com_err(whoami, 0, "Unable to find member %s to delete from %s",
276                       memberstruct->name, listname);
277             else if (status != SMS_SUCCESS)
278               com_err(whoami, status, " while deleteing member %s from %s",
279                       memberstruct->name, listname);
280         }
281     }
282
283     /* Display the members of the list now, if requested */
284     if (memberflg)
285         display_list_members();
286
287     /* We're done! */
288     sms_disconnect();
289     exit(0);
290 }
291
292 usage(argv)
293 char **argv;
294 {
295     fprintf(stderr, "Usage: %s [options] listname [options]\n",argv[0]);
296     fprintf(stderr, "Options are\n");
297     fprintf(stderr, "   -v | -verbose\n");
298     fprintf(stderr, "   -m | -members\n");
299     fprintf(stderr, "   -i | -info\n");
300     fprintf(stderr, "   -r | -recursive\n");
301     fprintf(stderr, "   -a | -add member\n");
302     fprintf(stderr, "   -d | -delete member\n");
303     fprintf(stderr, "   -f | -file filename\n");
304 #ifdef notdef
305     fprintf(stderr, "   -D | -debug\n");
306 #endif
307     exit(1);
308 }
309
310
311 show_list_members(memberlist)
312   struct sq *memberlist;
313 {
314     struct member *memberstruct;
315
316     while (sq_get_data(memberlist, &memberstruct)) {
317         if (verbose) {
318             char *s;
319             switch (memberstruct->type) {
320               case M_USER:
321                 s = "USER";
322                 break;
323               case M_LIST:
324                 s = "LIST";
325                 break;
326               case M_STRING:
327                 s = "STRING";
328                 break;
329             }
330             printf("%s:%s\n", s, memberstruct->name);
331         } else {
332             if (memberstruct->type == M_LIST)
333                 printf("LIST:%s\n", memberstruct->name);
334             else if (memberstruct->type == M_STRING &&
335                      !index(memberstruct->name, '@'))
336                 printf("STRING:%s\n", memberstruct->name);
337             else
338                 printf("%s\n", memberstruct->name);
339         }
340     }
341 }
342
343 show_list_info(argc, argv, hint)
344 int argc;
345 char **argv;
346 int hint;
347 {
348     printf("List: %s\n", argv[0]);
349     printf("Description: %s\n", argv[9]);
350     printf("Flags: %s, %s, and %s\n",
351            atoi(argv[1]) ? "active" : "inactive",
352            atoi(argv[2]) ? "public" : "private",
353            atoi(argv[3]) ? "hidden" : "visible");
354     printf("%s is %sa maillist and is %sa group", argv[0],
355            atoi(argv[4]) ? "" : "not ",
356            atoi(argv[5]) ? "" : "not ");
357     if (atoi(argv[5]))
358       printf(" with GID %d\n", atoi(argv[6]));
359     else
360       printf("\n");
361     printf("Owner: %s %s\n", argv[7], argv[8]);
362     printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
363     return(SMS_CONT);
364 }
365
366
367 show_list_count(argc, argv, hint)
368 int argc;
369 char **argv;
370 int hint;
371 {
372     printf("Members: %s\n", argv[0]);
373 }
374
375
376 display_list_members()
377 {
378     int status;
379
380     status = sms_query("get_members_of_list", 1, &listname,
381                        get_list_members, (char *)memberlist);
382     if (status)
383         com_err(whoami, status, " while getting members of list");
384     if (recursflg) 
385         fprintf(stderr,"%s: The recursive flag is not yet implemented.\n",
386                 whoami);
387     show_list_members(memberlist);
388 }
389
390 get_list_members(argc, argv, q)
391 int argc;
392 char **argv;
393 struct save_queue *q;
394 {
395     struct member *m;
396
397     m = (struct member *) malloc(sizeof(struct member));
398     switch (argv[0][0]) {
399     case 'U':
400         m->type = M_USER;
401         break;
402     case 'L':
403         m->type = M_LIST;
404         break;
405     case 'S':
406         m->type = M_STRING;
407         break;
408     }
409     m->name = strsave(argv[1]);
410     sq_save_data(q, m);
411     return(SMS_CONT);
412 }
413
414
415 scream()
416 {
417     fprintf(stderr, "Programmer botch\n");
418     exit(3);
419 }
420
421
422 struct member *parse_member(s)
423 register char *s;
424 {
425     register struct member *m;
426     char *p;
427
428     while (*s && isspace(*s))
429       s++;
430     p = s;
431     while (*p && isprint(*p) && !isspace(*p) && *p != ';')
432       p++;
433     *p = 0;
434     if (p == s || strlen(s) == 0)
435       return(NULL);
436
437     if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
438       return(NULL);
439
440     if (p = index(s, ':')) {
441         *p = 0;
442         m->name = ++p;
443         if (!strcasecmp("user", s))
444           m->type = M_USER;
445         else if (!strcasecmp("list", s))
446           m->type = M_LIST;
447         else if (!strcasecmp("string", s))
448           m->type = M_STRING;
449         else {
450             m->type = M_STRING;
451             *(--p) = ':';
452             m->name = s;
453         }
454         m->name = strsave(m->name);
455         return(m);
456     }
457     m->name = strsave(s);
458     if (index(s, '@') || index(s, '!') || index(s, '%'))
459       m->type = M_STRING;
460     else
461       m->type = M_ANY;
462     return(m);
463 }
464
465
466 int membercmp(m1, m2)
467   struct member *m1, *m2;
468   /* 
469    * This routine two compares members by the following rules:
470    * 1.  A USER is less than a LIST
471    * 2.  A LIST is less than a STRING
472    * 3.  If two members are of the same type, the one alphabetically first
473    *     is less than the other
474    * It returs < 0 if the first member is less, 0 if they are identical, and
475    * > 0 if the second member is less (the first member is greater).
476    */
477 {
478     if (m1->type == M_ANY || m2->type  == M_ANY || (m1->type == m2->type))
479         return(strcmp(m1->name, m2->name));
480     else
481         return(m1->type - m2->type);
482 }
This page took 0.070317 seconds and 5 git commands to generate.