]> andersk Git - moira.git/blame_incremental - clients/blanche/blanche.c
randomized continuation lines
[moira.git] / clients / blanche / blanche.c
... / ...
CommitLineData
1/* $Header$
2 *
3 * Command line oriented Moira 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 <errno.h>
19#include <stdio.h>
20#include <ctype.h>
21#include <string.h>
22#include <moira.h>
23#include <moira_site.h>
24
25#ifndef LINT
26static char blanche_rcsid[] = "$Header$";
27#endif
28
29
30struct member {
31 int type;
32 char *name;
33};
34
35/* It is important to membercmp that M_USER < M_LIST < M_STRING */
36#define M_ANY 0
37#define M_USER 1
38#define M_LIST 2
39#define M_STRING 3
40#define M_KERBEROS 4
41
42/* argument parsing macro */
43#define argis(a,b) ((strcmp(*arg+1, a) == 0) || (strcmp(*arg+1, b) == 0))
44
45/* flags from command line */
46int infoflg, verbose, syncflg, memberflg, recursflg, debugflg, noauth;
47int showusers, showstrings, showkerberos, showlists;
48
49/* various member lists */
50struct save_queue *addlist, *dellist, *memberlist, *synclist;
51
52char *listname, *whoami;
53
54#ifndef POSIX
55extern int errno;
56#endif
57
58int show_list_info(), show_list_count(), get_list_members(), scream();
59int show_list_members(), membercmp();
60struct member *parse_member();
61
62
63
64main(argc, argv)
65int argc;
66char **argv;
67{
68 int status;
69 char **arg = argv;
70 char *membervec[3], *motd;
71 struct member *memberstruct;
72 char *server = NULL, *p;
73
74 /* clear all flags & lists */
75 infoflg = verbose = syncflg = memberflg = debugflg = recursflg = 0;
76 noauth = showusers = showstrings = showkerberos = showlists = 0;
77 listname = NULL;
78 addlist = sq_create();
79 dellist = sq_create();
80 memberlist = sq_create();
81 synclist = sq_create();
82 whoami = argv[0];
83
84 /* parse args, building addlist, dellist, & synclist */
85 while (++arg - argv < argc) {
86 if (**arg == '-')
87 {
88 if (argis("m", "members"))
89 memberflg++;
90 else if (argis("u", "users"))
91 showusers++;
92 else if (argis("s", "strings"))
93 showstrings++;
94 else if (argis("l", "lists"))
95 showlists++;
96 else if (argis("k", "kerberos"))
97 showkerberos++;
98 else if (argis("D", "debug"))
99 debugflg++;
100 else if (argis("i","info"))
101 infoflg++;
102 else if (argis("n","noauth"))
103 noauth++;
104 else if (argis("v","verbose"))
105 verbose++;
106 else if (argis("r","recursive"))
107 recursflg++;
108 else if (argis("S","server"))
109 if (arg - argv < argc - 1) {
110 ++arg;
111 server = *arg;
112 } else
113 usage(argv);
114 else if (argis("a","add"))
115 if (arg - argv < argc - 1) {
116 ++arg;
117 if (memberstruct = parse_member(*arg))
118 sq_save_data(addlist, memberstruct);
119 } else
120 usage(argv);
121 else if (argis("al","addlist"))
122 if (arg - argv < argc - 1) {
123 ++arg;
124 get_members_from_file(*arg, addlist);
125 } else
126 usage(argv);
127 else if (argis("d","delete"))
128 if (arg - argv < argc - 1) {
129 ++arg;
130 if (memberstruct = parse_member(*arg))
131 sq_save_data(dellist, memberstruct);
132 } else
133 usage(argv);
134 else if (argis("dl","deletelist"))
135 if (arg - argv < argc - 1) {
136 ++arg;
137 get_members_from_file(*arg, dellist);
138 } else
139 usage(argv);
140 else if (argis("f","file"))
141 if (arg - argv < argc - 1) {
142 syncflg++;
143 ++arg;
144 get_members_from_file(*arg, synclist);
145 } else
146 usage(argv);
147 else
148 usage(argv);
149 }
150 else if (listname == NULL)
151 listname = *arg;
152 else
153 usage(argv);
154 }
155 if (listname == NULL)
156 usage(argv);
157
158 /* if no other options specified, turn on list members flag */
159 if (!(infoflg || syncflg ||
160 addlist->q_next != addlist || dellist->q_next != dellist))
161 memberflg++;
162
163 /* If none of {users,strings,lists,kerberos} specified, turn them all on */
164 if (!(showusers || showstrings || showlists || showkerberos))
165 showusers = showstrings = showlists = showkerberos = 1;
166
167 /* fire up Moira */
168 if (status = mr_connect(server)) {
169 com_err(whoami, status, "unable to connect to the Moira server");
170 exit(2);
171 }
172 if ( status = mr_motd(&motd) ) {
173 com_err(whoami, status, "unable to check server status");
174 exit(2);
175 }
176 if (motd) {
177 fprintf(stderr, "The Moira server is currently unavailable:\n%s\n", motd);
178 mr_disconnect();
179 exit(2);
180 }
181
182 if (!noauth && (status = mr_auth("blanche"))) {
183 if (status == MR_USER_AUTH)
184 com_err(whoami, status, "");
185 else {
186 com_err(whoami, status, "unable to authenticate to Moira");
187 com_err(whoami, 0,
188 " Try the -noauth flag if you don't need authentication");
189 exit(2);
190 }
191 }
192
193 /* display list info if requested to */
194 if (infoflg) {
195 status = mr_query("get_list_info", 1, &listname, show_list_info,NULL);
196 if (status)
197 com_err(whoami, status, "while getting list information");
198 if (verbose && !memberflg) {
199 status = mr_query("count_members_of_list", 1, &listname,
200 show_list_count, NULL);
201 if (status)
202 com_err(whoami, status, "while getting list count");
203 }
204 }
205
206 /* if we're synchronizing to a file, we need to:
207 * get the current members of the list
208 * for each member of the sync file
209 * if they are on the list, remove them from the in-memory copy
210 * if they're not on the list, add them to add-list
211 * if anyone is left on the in-memory copy, put them on the delete-list
212 * lastly, reset memberlist so we can use it again later
213 */
214 if (syncflg) {
215 status = mr_query("get_members_of_list", 1, &listname,
216 get_list_members, (char *)memberlist);
217 if (status)
218 com_err(whoami, status, "getting members of list %s", listname);
219 while (sq_get_data(synclist, &memberstruct)) {
220 struct save_queue *q;
221 int removed = 0;
222
223 for (q = memberlist->q_next; q != memberlist; q = q->q_next) {
224 if (membercmp(q->q_data, memberstruct) == 0) {
225 q->q_prev->q_next = q->q_next;
226 q->q_next->q_prev = q->q_prev;
227 removed++;
228 break;
229 }
230 }
231 if (!removed)
232 sq_save_data(addlist, memberstruct);
233 }
234 while (sq_get_data(memberlist, &memberstruct))
235 sq_save_data(dellist, memberstruct);
236 sq_destroy(memberlist);
237 memberlist = sq_create();
238 }
239
240 /* Process the add list */
241 while (sq_get_data(addlist, &memberstruct)) {
242 /* canonicalize string if necessary */
243 if (memberstruct->type == M_STRING &&
244 (p = strchr(memberstruct->name, '@'))) {
245 char *host = canonicalize_hostname(strsave(++p));
246 static char **mailhubs = NULL;
247 char *argv[4];
248 int i, collect();
249
250 if (!mailhubs) {
251 argv[0] = "mailhub";
252 argv[1] = "TYPE";
253 argv[2] = "*";
254 mailhubs = (char **)malloc(sizeof(char *));
255 mailhubs[0] = NULL;
256 status = mr_query("get_alias", 3, argv, collect,
257 (char *)&mailhubs);
258 if (status != MR_SUCCESS && status != MR_NO_MATCH) {
259 com_err(whoami, status,
260 " while reading list of MAILHUB servers");
261 mailhubs[0] = NULL;
262 }
263 }
264 for (i = 0; p = mailhubs[i]; i++) {
265 if (!strcasecmp(p, host)) {
266 host = strsave(memberstruct->name);
267 *(strchr(memberstruct->name, '@')) = 0;
268 memberstruct->type = M_ANY;
269 fprintf(stderr, "Warning: \"STRING:%s\" converted to \"%s\" because it is a local name.\n",
270 host, memberstruct->name);
271 break;
272 }
273 }
274 free(host);
275 }
276 /* now continue adding member */
277 membervec[0] = listname;
278 membervec[2] = memberstruct->name;
279 if (verbose) {
280 printf("Adding member ");
281 show_list_member(memberstruct);
282 }
283 switch (memberstruct->type) {
284 case M_ANY:
285 case M_USER:
286 membervec[1] = "USER";
287 status = mr_query("add_member_to_list", 3, membervec, scream, NULL);
288 if (status == MR_SUCCESS)
289 break;
290 else if (status != MR_USER || memberstruct->type != M_ANY) {
291 com_err(whoami, status, "while adding member %s to %s",
292 memberstruct->name, listname);
293 break;
294 }
295 case M_LIST:
296 membervec[1] = "LIST";
297 status = mr_query("add_member_to_list", 3, membervec,
298 scream, NULL);
299 if (status == MR_SUCCESS)
300 break;
301 else if (status != MR_LIST || memberstruct->type != M_ANY) {
302 com_err(whoami, status, "while adding member %s to %s",
303 memberstruct->name, listname);
304 break;
305 }
306 case M_STRING:
307 membervec[1] = "STRING";
308 status = mr_query("add_member_to_list", 3, membervec,
309 scream, NULL);
310 if (status != MR_SUCCESS)
311 com_err(whoami, status, "while adding member %s to %s",
312 memberstruct->name, listname);
313 break;
314 case M_KERBEROS:
315 membervec[1] = "KERBEROS";
316 status = mr_query("add_member_to_list", 3, membervec,
317 scream, NULL);
318 if (status != MR_SUCCESS)
319 com_err(whoami, status, "while adding member %s to %s",
320 memberstruct->name, listname);
321 }
322 }
323
324 /* Process the delete list */
325 while (sq_get_data(dellist, &memberstruct)) {
326 membervec[0] = listname;
327 membervec[2] = memberstruct->name;
328 if (verbose) {
329 printf("Deleting member ");
330 show_list_member(memberstruct);
331 }
332 switch (memberstruct->type) {
333 case M_ANY:
334 case M_USER:
335 membervec[1] = "USER";
336 status = mr_query("delete_member_from_list", 3, membervec,
337 scream, NULL);
338 if (status == MR_SUCCESS)
339 break;
340 else if ((status != MR_USER && status != MR_NO_MATCH) ||
341 memberstruct->type != M_ANY) {
342 com_err(whoami, status, "while deleting member %s from %s",
343 memberstruct->name, listname);
344 break;
345 }
346 case M_LIST:
347 membervec[1] = "LIST";
348 status = mr_query("delete_member_from_list", 3, membervec,
349 scream, NULL);
350 if (status == MR_SUCCESS)
351 break;
352 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
353 memberstruct->type != M_ANY) {
354 if (status == MR_PERM && memberstruct->type == M_ANY) {
355 /* M_ANY means we've fallen through from the user case
356 * The fact that we didn't get MR_PERM there indicates
357 * that we had permission to remove the specified member
358 * from the list if it is a user, but not a list. This is
359 * if we are the member in question. Since we exist as a user
360 * we must have gotten the MR_NO_MATCH error, so we will
361 * return that, since it will be less confusing. However,
362 * This will generate the wrongerror if the user was trying
363 * to remove the list with his/her username from a list they
364 * don't administrate, without explicitly specifying "list:".
365 */
366 status = MR_NO_MATCH;
367 }
368 com_err(whoami, status, "while deleting member %s from %s",
369 memberstruct->name, listname);
370 break;
371 }
372 case M_STRING:
373 membervec[1] = "STRING";
374 status = mr_query("delete_member_from_list", 3, membervec,
375 scream, NULL);
376 if (status == MR_STRING && memberstruct->type == M_ANY)
377 com_err(whoami, 0, " Unable to find member %s to delete from %s",
378 memberstruct->name, listname);
379 else if (status != MR_SUCCESS)
380 com_err(whoami, status, "while deleting member %s from %s",
381 memberstruct->name, listname);
382 break;
383 case M_KERBEROS:
384 membervec[1] = "KERBEROS";
385 status = mr_query("delete_member_from_list", 3, membervec,
386 scream, NULL);
387 if (status != MR_SUCCESS)
388 com_err(whoami, status, "while deleting member %s from %s",
389 memberstruct->name, listname);
390 }
391 }
392
393 /* Display the members of the list now, if requested */
394 if (memberflg) {
395 if (recursflg)
396 recursive_display_list_members();
397 else {
398 status = mr_query("get_members_of_list", 1, &listname,
399 get_list_members, (char *)memberlist);
400 if (status)
401 com_err(whoami, status, "while getting members of list %s",
402 listname);
403 while (sq_get_data(memberlist, &memberstruct))
404 show_list_member(memberstruct);
405 }
406 }
407
408 /* We're done! */
409 mr_disconnect();
410 exit(0);
411}
412
413usage(argv)
414char **argv;
415{
416 fprintf(stderr, "Usage: %s listname [options]\n",argv[0]);
417 fprintf(stderr, "Options are\n");
418 fprintf(stderr, " -v | -verbose\n");
419 fprintf(stderr, " -m | -members\n");
420 fprintf(stderr, " -u | -users\n");
421 fprintf(stderr, " -l | -lists\n");
422 fprintf(stderr, " -s | -strings\n");
423 fprintf(stderr, " -k | -kerberos\n");
424 fprintf(stderr, " -i | -info\n");
425 fprintf(stderr, " -r | -recursive\n");
426 fprintf(stderr, " -a | -add member\n");
427 fprintf(stderr, " -d | -delete member\n");
428 fprintf(stderr, " -al | -addlist filename\n");
429 fprintf(stderr, " -dl | -deletelist filename\n");
430 fprintf(stderr, " -f | -file filename\n");
431 fprintf(stderr, " -n | -noauth\n");
432 fprintf(stderr, " -S | -server host[:port]\n");
433 fprintf(stderr, " -D | -debug\n");
434 exit(1);
435}
436
437
438/* Display the members stored in the queue */
439
440show_list_member(memberstruct)
441struct member *memberstruct;
442{
443 char *s = "";
444
445 switch (memberstruct->type) {
446 case M_USER:
447 if (!showusers)
448 return;
449 s = "USER";
450 break;
451 case M_LIST:
452 if (!showlists)
453 return;
454 s = "LIST";
455 break;
456 case M_STRING:
457 if (!showstrings)
458 return;
459 s = "STRING";
460 break;
461 case M_KERBEROS:
462 if (!showkerberos)
463 return;
464 s = "KERBEROS";
465 break;
466 case M_ANY:
467 printf("%s\n", memberstruct->name);
468 return;
469 }
470
471 if (verbose)
472 printf("%s:%s\n", s, memberstruct->name);
473 else {
474 if (memberstruct->type == M_LIST)
475 printf("LIST:%s\n", memberstruct->name);
476 else if (memberstruct->type == M_KERBEROS)
477 printf("KERBEROS:%s\n", memberstruct->name);
478 else if (memberstruct->type == M_STRING &&
479 !strchr(memberstruct->name, '@'))
480 printf("STRING:%s\n", memberstruct->name);
481 else
482 printf("%s\n", memberstruct->name);
483 }
484}
485
486
487/* Show the retrieved information about a list */
488
489show_list_info(argc, argv, hint)
490int argc;
491char **argv;
492int hint;
493{
494 printf("List: %s\n", argv[0]);
495 printf("Description: %s\n", argv[9]);
496 printf("Flags: %s, %s, and %s\n",
497 atoi(argv[1]) ? "active" : "inactive",
498 atoi(argv[2]) ? "public" : "private",
499 atoi(argv[3]) ? "hidden" : "visible");
500 printf("%s is %sa maillist and is %sa group", argv[0],
501 atoi(argv[4]) ? "" : "not ",
502 atoi(argv[5]) ? "" : "not ");
503 if (atoi(argv[5]))
504 printf(" with GID %d\n", atoi(argv[6]));
505 else
506 printf("\n");
507 printf("Owner: %s %s\n", argv[7], argv[8]);
508 printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
509 return(MR_CONT);
510}
511
512
513/* Show the retrieve list member count */
514
515show_list_count(argc, argv, hint)
516int argc;
517char **argv;
518int hint;
519{
520 printf("Members: %s\n", argv[0]);
521}
522
523
524/* Recursively find all of the members of listname, and then display them */
525
526recursive_display_list_members()
527{
528 int status, count, savecount;
529 struct save_queue *lists, *members;
530 struct member *m, *m1, *data;
531
532 lists = sq_create();
533 members = sq_create();
534 m = (struct member *) malloc(sizeof(struct member));
535 m->type = M_LIST;
536 m->name = listname;
537 sq_save_data(lists, m);
538
539 while (sq_get_data(lists, &m)) {
540 sq_destroy(memberlist);
541 memberlist = sq_create();
542 if (debugflg)
543 fprintf(stderr, "Fetching members of %s\n", m->name);
544 status = mr_query("get_members_of_list", 1, &(m->name),
545 get_list_members, (char *)memberlist);
546 if (status)
547 com_err(whoami, status, "while getting members of list %s", m->name);
548 while (sq_get_data(memberlist, &m1)) {
549 if (m1->type == M_LIST)
550 unique_add_member(lists, m1);
551 else
552 unique_add_member(members, m1);
553 }
554 }
555 savecount = count = sq_count_elts(members);
556 data = (struct member *) malloc(count * sizeof(struct member));
557 count = 0;
558 while (sq_get_data(members, &m))
559 memcpy(&data[count++], m, sizeof(struct member));
560 qsort(data, count, sizeof(struct member), membercmp);
561 for (count = 0; count < savecount; count++) {
562 show_list_member(&data[count]);
563 }
564}
565
566
567/* add a struct member to a queue if that member isn't already there. */
568
569unique_add_member(q, m)
570struct save_queue *q;
571struct member *m;
572{
573 struct save_queue *qp;
574
575 for (qp = q->q_next; qp != q; qp = qp->q_next) {
576 if (!membercmp(qp->q_data, m))
577 return;
578 }
579 sq_save_data(q, m);
580}
581
582
583/* Collect the retrieved members of the list */
584
585get_list_members(argc, argv, q)
586int argc;
587char **argv;
588struct save_queue *q;
589{
590 struct member *m;
591
592 m = (struct member *) malloc(sizeof(struct member));
593 switch (argv[0][0]) {
594 case 'U':
595 m->type = M_USER;
596 break;
597 case 'L':
598 m->type = M_LIST;
599 break;
600 case 'S':
601 m->type = M_STRING;
602 break;
603 case 'K':
604 m->type = M_KERBEROS;
605 break;
606 }
607 m->name = strsave(argv[1]);
608 sq_save_data(q, m);
609 return(MR_CONT);
610}
611
612
613/* Called only if a query returns a value that we weren't expecting */
614
615scream()
616{
617 fprintf(stderr, "Programmer botch\n");
618 exit(3);
619}
620
621
622/* Open file, parse members from file, and put them on the specified queue */
623get_members_from_file(filename, queue)
624char *filename;
625struct save_queue *queue;
626{
627 FILE *in;
628 char buf[BUFSIZ];
629 struct member *memberstruct;
630
631 if (!strcmp(filename, "-"))
632 in = stdin;
633 else {
634 in = fopen(filename, "r");
635 if (!in) {
636 com_err(whoami, errno, "while opening %s for input", filename);
637 exit(2);
638 }
639 }
640
641 while (fgets(buf, BUFSIZ, in))
642 if (memberstruct = parse_member(buf))
643 sq_save_data(queue, memberstruct);
644 if (!feof(in))
645 com_err(whoami, errno, "while reading from %s", filename);
646}
647
648
649/* Collect the possible expansions of the alias MAILHUB */
650
651int collect(argc, argv, list)
652int argc;
653char **argv;
654char ***list;
655{
656 int i;
657
658 for (i = 0; (*list)[i]; i++);
659 *list = (char **)realloc(*list, (i + 2) * sizeof(char *));
660 (*list)[i] = strsave(argv[2]);
661 (*list)[i+1] = NULL;
662 return(MR_CONT);
663}
664
665
666/* Parse a line of input, fetching a member. NULL is returned if a member
667 * is not found. ';' is a comment character.
668 */
669
670struct member *parse_member(s)
671register char *s;
672{
673 register struct member *m;
674 char *p, *lastchar;
675
676 while (*s && isspace(*s))
677 s++;
678 lastchar = p = s;
679 while (*p && *p != '\n' && *p != ';')
680 if (isprint(*p) && !isspace(*p))
681 lastchar = p++;
682 else
683 p++;
684 lastchar++;
685 *lastchar = 0;
686 if (p == s || strlen(s) == 0)
687 return(NULL);
688
689 if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
690 return(NULL);
691
692 if (p = strchr(s, ':')) {
693 *p = 0;
694 m->name = ++p;
695 if (!strcasecmp("user", s))
696 m->type = M_USER;
697 else if (!strcasecmp("list", s))
698 m->type = M_LIST;
699 else if (!strcasecmp("string", s))
700 m->type = M_STRING;
701 else if (!strcasecmp("kerberos", s))
702 m->type = M_KERBEROS;
703 else {
704 m->type = M_STRING;
705 *(--p) = ':';
706 m->name = s;
707 }
708 m->name = strsave(m->name);
709 } else {
710 m->name = strsave(s);
711 if (strchr(s, '@') || strchr(s, '!') || strchr(s, '%') || strchr(s, ' '))
712 m->type = M_STRING;
713 else
714 m->type = M_ANY;
715 }
716 return(m);
717}
718
719
720 /*
721 * This routine two compares members by the following rules:
722 * 1. A USER is less than a LIST
723 * 2. A LIST is less than a STRING
724 * 3. If two members are of the same type, the one alphabetically first
725 * is less than the other
726 * It returs < 0 if the first member is less, 0 if they are identical, and
727 * > 0 if the second member is less (the first member is greater).
728 */
729
730int membercmp(m1, m2)
731 struct member *m1, *m2;
732{
733 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
734 return(strcmp(m1->name, m2->name));
735 else
736 return(m1->type - m2->type);
737}
738
739
740sq_count_elts(q)
741struct save_queue *q;
742{
743 char *foo;
744 int count;
745
746 count = 0;
747 while (sq_get_data(q, &foo))
748 count++;
749 return(count);
750}
This page took 0.05018 seconds and 5 git commands to generate.