]> andersk Git - moira.git/blame - clients/blanche/blanche.c
add server name to sms_conect call
[moira.git] / clients / blanche / blanche.c
CommitLineData
2d7360ca 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.
1b6b0a57 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>.
2d7360ca 12 */
13
1b6b0a57 14/* ### Aren't there a lot of sq abstraction barrier violations here?
15 Do we need to improve the support for queue operations? */
16
2d7360ca 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
24static char smslist_rcsid[] = "$Header$";
25#endif
26
27
28struct member {
29 int type;
30 char *name;
31};
32
b5b167d6 33/* It is important to membercmp that M_USER < M_LIST < M_STRING */
2d7360ca 34#define M_ANY 0
35#define M_USER 1
36#define M_LIST 2
37#define M_STRING 3
38
1b6b0a57 39/* argument parsing macro */
40#define argis(a,b) ((strcmp(*arg+1, a) == 0) || (strcmp(*arg+1, b) == 0))
41
2d7360ca 42/* flags from command line */
1b6b0a57 43int infoflg, verbose, syncflg, memberflg, recursflg, debugflg;
2d7360ca 44
45/* various member lists */
46struct save_queue *addlist, *dellist, *memberlist, *synclist;
47
48char *listname, *whoami;
49
50extern char *index();
51extern int errno;
52
53int show_list_info(), show_list_count(), get_list_members(), scream();
1b6b0a57 54int show_list_members();
2d7360ca 55struct member *parse_member();
56
57
58
59main(argc, argv)
60int argc;
61char **argv;
62{
63 int status;
64 char **arg = argv;
65 char *membervec[3];
66 struct member *memberstruct;
67
68 /* clear all flags & lists */
1b6b0a57 69 infoflg = verbose = syncflg = memberflg = debugflg = recursflg = 0;
2d7360ca 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 == '-')
1b6b0a57 80 {
81 if (argis("m", "members"))
82 memberflg++;
83 else if (argis("D", "debug"))
84 debugflg++;
85 else if (argis("i","information"))
2d7360ca 86 infoflg++;
1b6b0a57 87 else if (argis("v","verbose"))
2d7360ca 88 verbose++;
1b6b0a57 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];
b5b167d6 109
1b6b0a57 110 syncflg++;
111 ++arg;
112 if (!strcmp(*arg, "-"))
b5b167d6 113 in = stdin;
1b6b0a57 114 else {
115 in = fopen(*arg, "r");
b5b167d6 116 if (!in) {
1b6b0a57 117 com_err(whoami, errno,
118 " while opening %s for input", *arg);
119 exit(2);
120 }
121 }
122 while (fgets(buf, BUFSIZ, in))
b5b167d6 123 if (memberstruct = parse_member(buf))
124 sq_save_data(synclist, memberstruct);
1b6b0a57 125 if (!feof(in))
b5b167d6 126 com_err(whoami, errno, " while reading from %s", *arg);
1b6b0a57 127 } else
b5b167d6 128 usage(argv);
1b6b0a57 129 else
2d7360ca 130 usage(argv);
1b6b0a57 131 }
2d7360ca 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 */
a4ed33c1 146 if (status = sms_connect(SMS_SERVER)) {
2d7360ca 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,
1b6b0a57 178 get_list_members, (char *)memberlist);
2d7360ca 179 if (status)
b5b167d6 180 com_err(whoami, status, " getting members of list %s", listname);
2d7360ca 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) {
1b6b0a57 186 if (membercmp(q->q_data, memberstruct) == 0) {
2d7360ca 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;
b5b167d6 206 if (verbose && syncflg) {
207 printf("Adding member ");
208 show_list_member(memberstruct);
209 }
2d7360ca 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;
b5b167d6 247 if (verbose && syncflg) {
248 printf("Deleting member ");
249 show_list_member(memberstruct);
250 }
2d7360ca 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 */
b5b167d6 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 }
2d7360ca 304
305 /* We're done! */
306 sms_disconnect();
307 exit(0);
308}
309
310usage(argv)
311char **argv;
312{
1b6b0a57 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");
1b6b0a57 322 fprintf(stderr, " -D | -debug\n");
2d7360ca 323 exit(1);
324}
325
326
b5b167d6 327/* Display the members stored in the queue */
1b6b0a57 328
b5b167d6 329show_list_member(memberstruct)
330struct 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;
1b6b0a57 347 }
b5b167d6 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);
1b6b0a57 357 }
358}
359
b5b167d6 360
361/* Show the retrieved information about a list */
362
2d7360ca 363show_list_info(argc, argv, hint)
364int argc;
365char **argv;
366int 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");
1b6b0a57 374 printf("%s is %sa maillist and is %sa group", argv[0],
2d7360ca 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
b5b167d6 387/* Show the retrieve list member count */
388
2d7360ca 389show_list_count(argc, argv, hint)
390int argc;
391char **argv;
392int hint;
393{
394 printf("Members: %s\n", argv[0]);
395}
396
397
b5b167d6 398/* Recursively find all of the members of listname, and then display them */
399
400recursive_display_list_members()
1b6b0a57 401{
b5b167d6 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
443unique_add_member(q, m)
444struct save_queue *q;
445struct member *m;
446{
447 struct save_queue *qp;
1b6b0a57 448
b5b167d6 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);
1b6b0a57 454}
455
b5b167d6 456
457/* Collect the retrieved members of the list */
458
2d7360ca 459get_list_members(argc, argv, q)
460int argc;
461char **argv;
462struct 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
b5b167d6 484/* Called only if a query returns a value that we weren't expecting */
485
2d7360ca 486scream()
487{
488 fprintf(stderr, "Programmer botch\n");
489 exit(3);
490}
491
492
b5b167d6 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
2d7360ca 498struct member *parse_member(s)
499register 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
1b6b0a57 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 */
b5b167d6 551
552int membercmp(m1, m2)
553 struct member *m1, *m2;
2d7360ca 554{
1b6b0a57 555 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
556 return(strcmp(m1->name, m2->name));
2d7360ca 557 else
1b6b0a57 558 return(m1->type - m2->type);
2d7360ca 559}
b5b167d6 560
561
562sq_count_elts(q)
563struct 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.166232 seconds and 5 git commands to generate.