]> andersk Git - moira.git/blame - clients/blanche/blanche.c
add acl and tag support, fix up zephyr support
[moira.git] / clients / blanche / blanche.c
CommitLineData
c441a31a 1/* $Id$
2d7360ca 2 *
d44cee72 3 * Command line oriented Moira List tool.
2d7360ca 4 *
5 * by Mark Rosenstein, September 1988.
6 *
7ac48069 7 * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology.
1b6b0a57 8 * For copying and distribution information, please see the file
9 * <mit-copyright.h>.
2d7360ca 10 */
11
12#include <mit-copyright.h>
7ac48069 13#include <moira.h>
14#include <moira_site.h>
2a12a5ec 15#include <mrclient.h>
7ac48069 16
17#include <ctype.h>
9eb9cfb9 18#include <errno.h>
2d7360ca 19#include <stdio.h>
7b58c1b9 20#include <stdlib.h>
f071d8a7 21#include <string.h>
2d7360ca 22
7ac48069 23RCSID("$Header$");
2d7360ca 24
25struct member {
5eaef520 26 int type;
27 char *name;
2d7360ca 28};
29
b5b167d6 30/* It is important to membercmp that M_USER < M_LIST < M_STRING */
2d7360ca 31#define M_ANY 0
32#define M_USER 1
33#define M_LIST 2
34#define M_STRING 3
8c3b414d 35#define M_KERBEROS 4
2d7360ca 36
1b6b0a57 37/* argument parsing macro */
5eaef520 38#define argis(a, b) (!strcmp(*arg + 1, a) || !strcmp(*arg + 1, b))
1b6b0a57 39
2d7360ca 40/* flags from command line */
763465b8 41int infoflg, verbose, syncflg, memberflg, recursflg, noauth;
8c3b414d 42int showusers, showstrings, showkerberos, showlists;
763465b8 43int createflag, setinfo, active, public, hidden, maillist, grouplist;
44struct member *owner;
45char *desc, *newname;
2d7360ca 46
47/* various member lists */
48struct save_queue *addlist, *dellist, *memberlist, *synclist;
49
50char *listname, *whoami;
51
7ac48069 52void usage(char **argv);
53void show_list_member(struct member *memberstruct);
54int show_list_info(int argc, char **argv, void *hint);
55int save_list_info(int argc, char **argv, void *hint);
56int show_list_count(int argc, char **argv, void *hint);
57void recursive_display_list_members(void);
58void unique_add_member(struct save_queue *q, struct member *m);
59int get_list_members(int argc, char **argv, void *sq);
60void get_members_from_file(char *filename, struct save_queue *queue);
61int collect(int argc, char **argv, void *l);
62struct member *parse_member(char *s);
63int membercmp(const void *mem1, const void *mem2);
64int sq_count_elts(struct save_queue *q);
2d7360ca 65
5eaef520 66int main(int argc, char **argv)
2d7360ca 67{
5eaef520 68 int status, success;
69 char **arg = argv;
2a12a5ec 70 char *membervec[3];
5eaef520 71 struct member *memberstruct;
72 char *server = NULL, *p;
73
74 /* clear all flags & lists */
75 infoflg = verbose = syncflg = memberflg = recursflg = 0;
76 noauth = showusers = showstrings = showkerberos = showlists = 0;
77 createflag = setinfo = 0;
78 active = public = hidden = maillist = grouplist = -1;
79 listname = newname = desc = NULL;
80 owner = NULL;
81 addlist = sq_create();
82 dellist = sq_create();
83 memberlist = sq_create();
84 synclist = sq_create();
85 whoami = argv[0];
86
87 success = 1;
88
89 /* parse args, building addlist, dellist, & synclist */
90 while (++arg - argv < argc)
91 {
92 if (**arg == '-')
1b6b0a57 93 {
5eaef520 94 if (argis("m", "members"))
95 memberflg++;
96 else if (argis("u", "users"))
97 showusers++;
98 else if (argis("s", "strings"))
99 showstrings++;
100 else if (argis("l", "lists"))
101 showlists++;
102 else if (argis("k", "kerberos"))
103 showkerberos++;
104 else if (argis("i", "info"))
105 infoflg++;
106 else if (argis("n", "noauth"))
107 noauth++;
108 else if (argis("v", "verbose"))
109 verbose++;
110 else if (argis("r", "recursive"))
111 recursflg++;
112 else if (argis("S", "server") || argis("db", "database"))
113 {
114 if (arg - argv < argc - 1)
115 {
116 ++arg;
117 server = *arg;
118 }
119 else
120 usage(argv);
121 }
122 else if (argis("a", "add"))
123 {
124 if (arg - argv < argc - 1)
125 {
126 ++arg;
127 if ((memberstruct = parse_member(*arg)))
128 sq_save_data(addlist, memberstruct);
129 }
130 else
131 usage(argv);
132 }
133 else if (argis("al", "addlist"))
134 {
135 if (arg - argv < argc - 1)
136 {
137 ++arg;
138 get_members_from_file(*arg, addlist);
139 }
140 else
141 usage(argv);
142 }
143 else if (argis("d", "delete"))
144 {
145 if (arg - argv < argc - 1)
146 {
147 ++arg;
148 if ((memberstruct = parse_member(*arg)))
149 sq_save_data(dellist, memberstruct);
150 }
151 else
152 usage(argv);
153 }
154 else if (argis("dl", "deletelist"))
155 {
156 if (arg - argv < argc - 1)
157 {
158 ++arg;
159 get_members_from_file(*arg, dellist);
160 }
161 else
162 usage(argv);
163 }
164 else if (argis("f", "file"))
165 {
166 if (arg - argv < argc - 1)
167 {
168 syncflg++;
169 ++arg;
170 get_members_from_file(*arg, synclist);
171 }
172 else
173 usage(argv);
174 }
175 else if (argis("C", "create"))
176 createflag++;
177 else if (argis("P", "public"))
178 {
179 setinfo++;
180 public = 1;
181 }
182 else if (argis("NP", "private"))
183 {
184 setinfo++;
185 public = 0;
186 }
187 else if (argis("A", "active"))
188 {
189 setinfo++;
190 active = 1;
191 }
192 else if (argis("I", "inactive"))
193 {
194 setinfo++;
195 active = 0;
196 }
197 else if (argis("V", "visible"))
198 {
199 setinfo++;
200 hidden = 0;
201 }
202 else if (argis("H", "hidden"))
203 {
204 setinfo++;
205 hidden = 1;
206 }
207 else if (argis("M", "mail"))
208 {
209 setinfo++;
210 maillist = 1;
211 }
212 else if (argis("NM", "notmail"))
213 {
214 setinfo++;
215 maillist = 0;
216 }
217 else if (argis("G", "group"))
218 {
219 setinfo++;
220 grouplist = 1;
221 }
222 else if (argis("NG", "notgroup"))
223 {
224 setinfo++;
225 grouplist = 0;
226 }
227 else if (argis("D", "desc"))
228 {
229 if (arg - argv < argc - 1)
230 {
231 setinfo++;
232 ++arg;
233 desc = *arg;
234 }
235 else
236 usage(argv);
237 }
238 else if (argis("O", "owner"))
239 {
240 if (arg - argv < argc - 1)
241 {
242 setinfo++;
243 ++arg;
244 owner = parse_member(*arg);
245 }
246 else
247 usage(argv);
248 }
249 else if (argis("R", "rename"))
250 {
251 if (arg - argv < argc - 1)
252 {
253 setinfo++;
254 ++arg;
255 newname = *arg;
256 }
257 else
2d7360ca 258 usage(argv);
5eaef520 259 }
260 else
261 usage(argv);
1b6b0a57 262 }
5eaef520 263 else if (listname == NULL)
264 listname = *arg;
265 else
266 usage(argv);
2d7360ca 267 }
5eaef520 268 if (listname == NULL)
269 usage(argv);
270
271 /* if no other options specified, turn on list members flag */
272 if (!(infoflg || syncflg || createflag || setinfo ||
273 addlist->q_next != addlist || dellist->q_next != dellist))
274 memberflg++;
275
276 /* If none of {users,strings,lists,kerberos} specified, turn them all on */
277 if (!(showusers || showstrings || showlists || showkerberos))
278 showusers = showstrings = showlists = showkerberos = 1;
279
280 /* fire up Moira */
acde26f0 281 status = mrcl_connect(server, "blanche", 2, !noauth);
2a12a5ec 282 if (status == MRCL_AUTH_ERROR)
5eaef520 283 {
2a12a5ec 284 com_err(whoami, 0, "Try the -noauth flag if you don't "
285 "need authentication.");
2d7360ca 286 }
2a12a5ec 287 if (status)
288 exit(2);
2d7360ca 289
84826a5d 290 /* check for username/listname clash */
291 if (createflag || (setinfo && newname && strcmp(newname, listname)))
292 {
293 status = mr_query("get_user_account_by_login", 1,
294 createflag ? &listname : &newname,
295 NULL, NULL);
296 if (status != MR_NO_MATCH)
297 fprintf(stderr, "WARNING: A user by that name already exists.\n");
298 }
299
5eaef520 300 /* create if needed */
301 if (createflag)
302 {
303 char *argv[10];
304
305 argv[0] = listname;
306 argv[1] = (active == 0) ? "0" : "1";
307 argv[2] = (public == 1) ? "1" : "0";
308 argv[3] = (hidden == 1) ? "1" : "0";
309 argv[4] = (maillist == 0) ? "0" : "1";
310 argv[5] = (grouplist == 1) ? "1" : "0";
311 argv[6] = UNIQUE_GID;
312 argv[9] = desc ? desc : "none";
313
314 if (owner)
315 {
316 argv[8] = owner->name;
317 switch (owner->type)
318 {
319 case M_ANY:
320 case M_USER:
321 argv[7] = "USER";
7ac48069 322 status = mr_query("add_list", 10, argv, NULL, NULL);
5eaef520 323 if (owner->type != M_ANY || status != MR_USER)
324 break;
325
326 case M_LIST:
327 argv[7] = "LIST";
7ac48069 328 status = mr_query("add_list", 10, argv, NULL, NULL);
5eaef520 329 break;
330
331 case M_KERBEROS:
332 argv[7] = "KERBEROS";
7ac48069 333 status = mr_query("add_list", 10, argv, NULL, NULL);
5eaef520 334 break;
335 }
763465b8 336 }
5eaef520 337 else
338 {
339 argv[7] = "USER";
340 argv[8] = getenv("USER");
341
7ac48069 342 status = mr_query("add_list", 10, argv, NULL, NULL);
763465b8 343 }
344
5eaef520 345 if (status)
346 {
347 com_err(whoami, status, "while creating list.");
348 exit(1);
349 }
763465b8 350 }
5eaef520 351 else if (setinfo)
352 {
353 char *argv[11];
763465b8 354
5eaef520 355 status = mr_query("get_list_info", 1, &listname,
7ac48069 356 save_list_info, argv);
5eaef520 357 if (status)
358 {
d44cee72 359 com_err(whoami, status, "while getting list information");
5eaef520 360 exit(1);
2d7360ca 361 }
5eaef520 362
363 argv[0] = listname;
364 if (newname)
365 argv[1] = newname;
366 if (active != -1)
367 argv[2] = active ? "1" : "0";
368 if (public != -1)
369 argv[3] = public ? "1" : "0";
370 if (hidden != -1)
371 argv[4] = hidden ? "1" : "0";
372 if (maillist != -1)
373 argv[5] = maillist ? "1" : "0";
374 if (grouplist != -1)
375 argv[6] = grouplist ? "1" : "0";
376 if (desc)
377 argv[10] = desc;
378
379 if (owner)
380 {
381 argv[9] = owner->name;
382 switch (owner->type)
383 {
384 case M_ANY:
385 case M_USER:
386 argv[8] = "USER";
7ac48069 387 status = mr_query("update_list", 11, argv, NULL, NULL);
5eaef520 388 if (owner->type != M_ANY || status != MR_USER)
389 break;
390
391 case M_LIST:
392 argv[8] = "LIST";
7ac48069 393 status = mr_query("update_list", 11, argv, NULL, NULL);
5eaef520 394 break;
395
396 case M_KERBEROS:
397 argv[8] = "KERBEROS";
7ac48069 398 status = mr_query("update_list", 11, argv, NULL, NULL);
5eaef520 399 break;
400 }
401 }
402 else
7ac48069 403 status = mr_query("update_list", 11, argv, NULL, NULL);
5eaef520 404
405 if (status)
e4d25787 406 {
407 com_err(whoami, status, "while updating list.");
408 success = 0;
409 }
5eaef520 410 else if (newname)
411 listname = newname;
2d7360ca 412 }
413
5eaef520 414 /* display list info if requested to */
415 if (infoflg)
416 {
417 status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
418 if (status)
e4d25787 419 {
420 com_err(whoami, status, "while getting list information");
421 success = 0;
422 }
5eaef520 423 if (verbose && !memberflg)
424 {
425 status = mr_query("count_members_of_list", 1, &listname,
426 show_list_count, NULL);
427 if (status)
e4d25787 428 {
429 com_err(whoami, status, "while getting list count");
430 success = 0;
431 }
26624cbe 432 }
5eaef520 433 }
434
435 /* if we're synchronizing to a file, we need to:
436 * get the current members of the list
437 * for each member of the sync file
438 * if they are on the list, remove them from the in-memory copy
439 * if they're not on the list, add them to add-list
440 * if anyone is left on the in-memory copy, put them on the delete-list
441 * lastly, reset memberlist so we can use it again later
442 */
443 if (syncflg)
444 {
445 status = mr_query("get_members_of_list", 1, &listname,
7ac48069 446 get_list_members, memberlist);
5eaef520 447 if (status)
448 {
449 com_err(whoami, status, "getting members of list %s", listname);
450 exit(2);
451 }
452 while (sq_get_data(synclist, &memberstruct))
453 {
454 struct save_queue *q;
455 int removed = 0;
456
457 for (q = memberlist->q_next; q != memberlist; q = q->q_next)
458 {
459 if (membercmp(q->q_data, memberstruct) == 0)
460 {
461 q->q_prev->q_next = q->q_next;
462 q->q_next->q_prev = q->q_prev;
463 removed++;
464 break;
2d7360ca 465 }
466 }
5eaef520 467 if (!removed)
468 sq_save_data(addlist, memberstruct);
2d7360ca 469 }
5eaef520 470 while (sq_get_data(memberlist, &memberstruct))
471 sq_save_data(dellist, memberstruct);
472 sq_destroy(memberlist);
473 memberlist = sq_create();
2d7360ca 474 }
475
5eaef520 476 /* Process the add list */
477 while (sq_get_data(addlist, &memberstruct))
478 {
479 /* canonicalize string if necessary */
2b3e2afe 480 if (memberstruct->type != M_KERBEROS &&
5eaef520 481 (p = strchr(memberstruct->name, '@')))
482 {
7ac48069 483 char *host = canonicalize_hostname(strdup(++p));
5eaef520 484 static char **mailhubs = NULL;
485 char *argv[4];
7ac48069 486 int i;
5eaef520 487
488 if (!mailhubs)
489 {
490 argv[0] = "mailhub";
491 argv[1] = "TYPE";
492 argv[2] = "*";
493 mailhubs = malloc(sizeof(char *));
494 mailhubs[0] = NULL;
495 status = mr_query("get_alias", 3, argv, collect,
7ac48069 496 &mailhubs);
5eaef520 497 if (status != MR_SUCCESS && status != MR_NO_MATCH)
498 {
499 com_err(whoami, status,
500 " while reading list of MAILHUB servers");
501 mailhubs[0] = NULL;
99bdafb8 502 }
503 }
5eaef520 504 for (i = 0; (p = mailhubs[i]); i++)
505 {
506 if (!strcasecmp(p, host))
507 {
7ac48069 508 host = strdup(memberstruct->name);
5eaef520 509 *(strchr(memberstruct->name, '@')) = 0;
2b3e2afe 510 if (memberstruct->type == M_STRING)
511 memberstruct->type = M_ANY;
512 fprintf(stderr, "Warning: \"%s\" converted to "
5eaef520 513 "\"%s\" because it is a local name.\n",
514 host, memberstruct->name);
515 break;
99bdafb8 516 }
517 }
5eaef520 518 free(host);
99bdafb8 519 }
5eaef520 520 /* now continue adding member */
521 membervec[0] = listname;
522 membervec[2] = memberstruct->name;
523 if (verbose)
524 {
525 printf("Adding member ");
526 show_list_member(memberstruct);
b5b167d6 527 }
5eaef520 528 switch (memberstruct->type)
529 {
2d7360ca 530 case M_ANY:
531 case M_USER:
5eaef520 532 membervec[1] = "USER";
7ac48069 533 status = mr_query("add_member_to_list", 3, membervec, NULL, NULL);
5eaef520 534 if (status == MR_SUCCESS)
535 break;
536 else if (status != MR_USER || memberstruct->type != M_ANY)
537 {
538 com_err(whoami, status, "while adding member %s to %s",
539 memberstruct->name, listname);
540 success = 0;
2d7360ca 541 break;
2d7360ca 542 }
543 case M_LIST:
5eaef520 544 membervec[1] = "LIST";
545 status = mr_query("add_member_to_list", 3, membervec,
7ac48069 546 NULL, NULL);
5eaef520 547 if (status == MR_SUCCESS)
548 {
549 if (!strcmp(membervec[0], getenv("USER")))
550 {
551 fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
552 "to list \"%s\".\n", membervec[2], membervec[0]);
553 fprintf(stderr, "If you meant to add yourself to the list "
554 "\"%s\", type:\n", membervec[2]);
555 fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
556 membervec[0], membervec[2]);
557 fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
558 "that list)\n", membervec[2], membervec[0]);
7b58c1b9 559 }
5eaef520 560 break;
561 }
562 else if (status != MR_LIST || memberstruct->type != M_ANY)
563 {
564 com_err(whoami, status, "while adding member %s to %s",
565 memberstruct->name, listname);
566 success = 0;
567 break;
2d7360ca 568 }
569 case M_STRING:
5eaef520 570 if (memberstruct->type == M_ANY &&
571 !strchr(memberstruct->name, '@') &&
572 !strchr(memberstruct->name, '!') &&
573 !strchr(memberstruct->name, '%'))
574 {
575 /* if user is trying to add something which isn't a
576 remote string, or a list, or a user, and didn't
577 explicitly specify `STRING:', it's probably a typo */
578 com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
579 memberstruct->name, listname);
580 success = 0;
581 break;
25978f25 582 }
5eaef520 583
584 membervec[1] = "STRING";
585 status = mr_query("add_member_to_list", 3, membervec,
7ac48069 586 NULL, NULL);
5eaef520 587 if (status != MR_SUCCESS)
588 {
d44cee72 589 com_err(whoami, status, "while adding member %s to %s",
2d7360ca 590 memberstruct->name, listname);
e681e918 591 success = 0;
592 }
5eaef520 593 break;
8c3b414d 594 case M_KERBEROS:
5eaef520 595 membervec[1] = "KERBEROS";
596 status = mr_query("add_member_to_list", 3, membervec,
7ac48069 597 NULL, NULL);
5eaef520 598 if (status != MR_SUCCESS)
599 {
d44cee72 600 com_err(whoami, status, "while adding member %s to %s",
8c3b414d 601 memberstruct->name, listname);
e681e918 602 success = 0;
603 }
2d7360ca 604 }
605 }
606
5eaef520 607 /* Process the delete list */
608 while (sq_get_data(dellist, &memberstruct))
609 {
610 membervec[0] = listname;
611 membervec[2] = memberstruct->name;
612 if (verbose)
613 {
614 printf("Deleting member ");
615 show_list_member(memberstruct);
b5b167d6 616 }
5eaef520 617 switch (memberstruct->type)
618 {
2d7360ca 619 case M_ANY:
620 case M_USER:
5eaef520 621 membervec[1] = "USER";
622 status = mr_query("delete_member_from_list", 3, membervec,
7ac48069 623 NULL, NULL);
5eaef520 624 if (status == MR_SUCCESS)
625 break;
626 else if ((status != MR_USER && status != MR_NO_MATCH) ||
627 memberstruct->type != M_ANY)
628 {
629 com_err(whoami, status, "while deleting member %s from %s",
630 memberstruct->name, listname);
631 success = 0;
2d7360ca 632 break;
2d7360ca 633 }
634 case M_LIST:
5eaef520 635 membervec[1] = "LIST";
636 status = mr_query("delete_member_from_list", 3, membervec,
7ac48069 637 NULL, NULL);
5eaef520 638 if (status == MR_SUCCESS)
639 break;
640 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
641 memberstruct->type != M_ANY)
642 {
643 if (status == MR_PERM && memberstruct->type == M_ANY &&
644 !strcmp(membervec[2], getenv("USER")))
645 {
646 /* M_ANY means we've fallen through from the user
647 * case. The user is trying to remove himself from
648 * a list, but we got MR_USER or MR_NO_MATCH above,
649 * meaning he's not really on it, and we got MR_PERM
650 * when trying to remove LIST:$USER because he's not
651 * on the acl. That error is useless, so return
652 * MR_NO_MATCH instead. However, this will generate the
653 * wrong error if the user was trying to remove the list
654 * with his username from a list he doesn't administrate
655 * without explicitly specifying "list:".
656 */
40637dba 657 status = MR_NO_MATCH;
658 }
5eaef520 659 com_err(whoami, status, "while deleting member %s from %s",
660 memberstruct->name, listname);
661 success = 0;
662 break;
2d7360ca 663 }
664 case M_STRING:
5eaef520 665 membervec[1] = "STRING";
666 status = mr_query("delete_member_from_list", 3, membervec,
7ac48069 667 NULL, NULL);
5eaef520 668 if (status == MR_STRING && memberstruct->type == M_ANY)
669 {
d44cee72 670 com_err(whoami, 0, " Unable to find member %s to delete from %s",
2d7360ca 671 memberstruct->name, listname);
e681e918 672 success = 0;
5eaef520 673 if (!strcmp(membervec[0], getenv("USER")))
674 {
675 fprintf(stderr, "(If you were trying to remove yourself "
676 "from the list \"%s\",\n", membervec[2]);
677 fprintf(stderr, "the correct command is \"blanche %s -d "
678 "%s\".)\n", membervec[2], membervec[0]);
679 }
680 }
681 else if (status != MR_SUCCESS)
682 {
d44cee72 683 com_err(whoami, status, "while deleting member %s from %s",
2d7360ca 684 memberstruct->name, listname);
e681e918 685 success = 0;
686 }
5eaef520 687 break;
8c3b414d 688 case M_KERBEROS:
5eaef520 689 membervec[1] = "KERBEROS";
690 status = mr_query("delete_member_from_list", 3, membervec,
7ac48069 691 NULL, NULL);
5eaef520 692 if (status != MR_SUCCESS)
693 {
d44cee72 694 com_err(whoami, status, "while deleting member %s from %s",
8c3b414d 695 memberstruct->name, listname);
e681e918 696 success = 0;
697 }
2d7360ca 698 }
699 }
700
5eaef520 701 /* Display the members of the list now, if requested */
702 if (memberflg)
703 {
704 if (recursflg)
705 recursive_display_list_members();
706 else
707 {
708 status = mr_query("get_members_of_list", 1, &listname,
7ac48069 709 get_list_members, memberlist);
5eaef520 710 if (status)
711 com_err(whoami, status, "while getting members of list %s",
712 listname);
713 while (sq_get_data(memberlist, &memberstruct))
714 show_list_member(memberstruct);
b5b167d6 715 }
716 }
2d7360ca 717
5eaef520 718 /* We're done! */
719 mr_disconnect();
720 exit(success ? 0 : 1);
2d7360ca 721}
722
7ac48069 723void usage(char **argv)
2d7360ca 724{
5eaef520 725 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
726 fprintf(stderr, "Options are\n");
727 fprintf(stderr, " %-39s%-39s\n", "-v | -verbose",
728 "-C | -create");
729 fprintf(stderr, " %-39s%-39s\n", "-m | -members",
730 "-R | -rename newname");
731 fprintf(stderr, " %-39s%-39s\n", "-u | -users",
732 "-P | -public");
733 fprintf(stderr, " %-39s%-39s\n", "-l | -lists",
734 "-NP | -private");
735 fprintf(stderr, " %-39s%-39s\n", "-s | -strings",
736 "-A | -active");
737 fprintf(stderr, " %-39s%-39s\n", "-k | -kerberos",
738 "-I | -inactive");
739 fprintf(stderr, " %-39s%-39s\n", "-i | -info",
740 "-V | -visible");
741 fprintf(stderr, " %-39s%-39s\n", "-r | -recursive",
742 "-H | -hidden");
743 fprintf(stderr, " %-39s%-39s\n", "-a | -add member",
744 "-M | -mail");
745 fprintf(stderr, " %-39s%-39s\n", "-d | -delete member",
746 "-NM | -notmail");
747 fprintf(stderr, " %-39s%-39s\n", "-al | -addlist filename",
748 "-G | -group");
749 fprintf(stderr, " %-39s%-39s\n", "-dl | -deletelist filename",
750 "-NG | -notgroup");
751 fprintf(stderr, " %-39s%-39s\n", "-f | -file filename",
752 "-D | -desc description");
753 fprintf(stderr, " %-39s%-39s\n", "-n | -noauth",
754 "-O | -owner owner");
755 fprintf(stderr, " %-39s%-39s\n", "-db | -database host[:port]",
756 "");
757 exit(1);
2d7360ca 758}
759
760
b5b167d6 761/* Display the members stored in the queue */
1b6b0a57 762
7ac48069 763void show_list_member(struct member *memberstruct)
b5b167d6 764{
5eaef520 765 char *s = "";
8b494222 766
5eaef520 767 switch (memberstruct->type)
768 {
8b494222 769 case M_USER:
5eaef520 770 if (!showusers)
771 return;
772 s = "USER";
773 break;
8b494222 774 case M_LIST:
5eaef520 775 if (!showlists)
776 return;
777 s = "LIST";
778 break;
8b494222 779 case M_STRING:
5eaef520 780 if (!showstrings)
781 return;
782 s = "STRING";
783 break;
8c3b414d 784 case M_KERBEROS:
5eaef520 785 if (!showkerberos)
8b494222 786 return;
5eaef520 787 s = "KERBEROS";
788 break;
789 case M_ANY:
790 printf("%s\n", memberstruct->name);
791 return;
8b494222 792 }
793
5eaef520 794 if (verbose)
795 printf("%s:%s\n", s, memberstruct->name);
796 else
797 {
798 if (memberstruct->type == M_LIST)
799 printf("LIST:%s\n", memberstruct->name);
800 else if (memberstruct->type == M_KERBEROS)
801 printf("KERBEROS:%s\n", memberstruct->name);
802 else if (memberstruct->type == M_STRING &&
803 !strchr(memberstruct->name, '@'))
804 printf("STRING:%s\n", memberstruct->name);
805 else
806 printf("%s\n", memberstruct->name);
1b6b0a57 807 }
808}
809
b5b167d6 810
811/* Show the retrieved information about a list */
812
7ac48069 813int show_list_info(int argc, char **argv, void *hint)
2d7360ca 814{
5eaef520 815 printf("List: %s\n", argv[0]);
816 printf("Description: %s\n", argv[9]);
817 printf("Flags: %s, %s, and %s\n",
818 atoi(argv[1]) ? "active" : "inactive",
819 atoi(argv[2]) ? "public" : "private",
820 atoi(argv[3]) ? "hidden" : "visible");
821 printf("%s is %sa maillist and is %sa group", argv[0],
822 atoi(argv[4]) ? "" : "not ",
823 atoi(argv[5]) ? "" : "not ");
824 if (atoi(argv[5]))
825 printf(" with GID %d\n", atoi(argv[6]));
826 else
827 printf("\n");
828 printf("Owner: %s %s\n", argv[7], argv[8]);
829 printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
830 return MR_CONT;
2d7360ca 831}
832
833
763465b8 834/* Copy retrieved information about a list into a new argv */
835
7ac48069 836int save_list_info(int argc, char **argv, void *hint)
763465b8 837{
7ac48069 838 char **nargv = hint;
5eaef520 839
840 for (argc = 0; argc < 10; argc++)
841 nargv[argc + 1] = strdup(argv[argc]);
842 return MR_CONT;
763465b8 843}
844
b5b167d6 845/* Show the retrieve list member count */
846
7ac48069 847int show_list_count(int argc, char **argv, void *hint)
2d7360ca 848{
5eaef520 849 printf("Members: %s\n", argv[0]);
7ac48069 850 return MR_CONT;
2d7360ca 851}
852
853
b5b167d6 854/* Recursively find all of the members of listname, and then display them */
855
7ac48069 856void recursive_display_list_members(void)
1b6b0a57 857{
5eaef520 858 int status, count, savecount;
859 struct save_queue *lists, *members;
860 struct member *m, *m1, *data;
861
862 lists = sq_create();
863 members = sq_create();
864 m = malloc(sizeof(struct member));
865 m->type = M_LIST;
866 m->name = listname;
867 sq_save_data(lists, m);
868
869 while (sq_get_data(lists, &m))
870 {
871 sq_destroy(memberlist);
872 memberlist = sq_create();
873 status = mr_query("get_members_of_list", 1, &(m->name),
7ac48069 874 get_list_members, memberlist);
5eaef520 875 if (status)
876 com_err(whoami, status, "while getting members of list %s", m->name);
877 while (sq_get_data(memberlist, &m1))
878 {
879 if (m1->type == M_LIST)
880 unique_add_member(lists, m1);
881 else
882 unique_add_member(members, m1);
b5b167d6 883 }
884 }
5eaef520 885 savecount = count = sq_count_elts(members);
886 data = malloc(count * sizeof(struct member));
887 count = 0;
888 while (sq_get_data(members, &m))
889 memcpy(&data[count++], m, sizeof(struct member));
890 qsort(data, count, sizeof(struct member), membercmp);
891 for (count = 0; count < savecount; count++)
892 show_list_member(&data[count]);
b5b167d6 893}
894
895
896/* add a struct member to a queue if that member isn't already there. */
897
7ac48069 898void unique_add_member(struct save_queue *q, struct member *m)
b5b167d6 899{
5eaef520 900 struct save_queue *qp;
1b6b0a57 901
5eaef520 902 for (qp = q->q_next; qp != q; qp = qp->q_next)
903 {
904 if (!membercmp(qp->q_data, m))
905 return;
b5b167d6 906 }
5eaef520 907 sq_save_data(q, m);
1b6b0a57 908}
909
b5b167d6 910
911/* Collect the retrieved members of the list */
912
7ac48069 913int get_list_members(int argc, char **argv, void *sq)
2d7360ca 914{
7ac48069 915 struct save_queue *q = sq;
5eaef520 916 struct member *m;
2d7360ca 917
5eaef520 918 m = malloc(sizeof(struct member));
919 switch (argv[0][0])
920 {
2d7360ca 921 case 'U':
5eaef520 922 m->type = M_USER;
923 break;
2d7360ca 924 case 'L':
5eaef520 925 m->type = M_LIST;
926 break;
2d7360ca 927 case 'S':
5eaef520 928 m->type = M_STRING;
929 break;
8c3b414d 930 case 'K':
5eaef520 931 m->type = M_KERBEROS;
932 break;
2d7360ca 933 }
7ac48069 934 m->name = strdup(argv[1]);
5eaef520 935 sq_save_data(q, m);
936 return MR_CONT;
2d7360ca 937}
938
939
7c02cbdb 940/* Open file, parse members from file, and put them on the specified queue */
7ac48069 941void get_members_from_file(char *filename, struct save_queue *queue)
7c02cbdb 942{
5eaef520 943 FILE *in;
944 char buf[BUFSIZ];
945 struct member *memberstruct;
946
947 if (!strcmp(filename, "-"))
948 in = stdin;
949 else
950 {
951 in = fopen(filename, "r");
952 if (!in)
953 {
954 com_err(whoami, errno, "while opening %s for input", filename);
955 exit(2);
7c02cbdb 956 }
957 }
958
5eaef520 959 while (fgets(buf, BUFSIZ, in))
960 {
961 if ((memberstruct = parse_member(buf)))
7c02cbdb 962 sq_save_data(queue, memberstruct);
5eaef520 963 }
964 if (!feof(in))
965 {
7c02cbdb 966 com_err(whoami, errno, "while reading from %s", filename);
e681e918 967 exit(2);
968 }
7c02cbdb 969}
970
971
99bdafb8 972/* Collect the possible expansions of the alias MAILHUB */
973
7ac48069 974int collect(int argc, char **argv, void *l)
99bdafb8 975{
7ac48069 976 char ***list = l;
5eaef520 977 int i;
978
979 for (i = 0; (*list)[i]; i++)
980 ;
981 *list = realloc(*list, (i + 2) * sizeof(char *));
7ac48069 982 (*list)[i] = strdup(argv[2]);
5eaef520 983 (*list)[i + 1] = NULL;
984 return MR_CONT;
99bdafb8 985}
986
987
b5b167d6 988/* Parse a line of input, fetching a member. NULL is returned if a member
7c02cbdb 989 * is not found. ';' is a comment character.
b5b167d6 990 */
991
44d12d58 992struct member *parse_member(char *s)
2d7360ca 993{
44d12d58 994 struct member *m;
5eaef520 995 char *p, *lastchar;
996
997 while (*s && isspace(*s))
998 s++;
999 lastchar = p = s;
1000 while (*p && *p != '\n' && *p != ';')
1001 {
7c02cbdb 1002 if (isprint(*p) && !isspace(*p))
1003 lastchar = p++;
1004 else
1005 p++;
5eaef520 1006 }
1007 lastchar++;
1008 *lastchar = '\0';
1009 if (p == s || strlen(s) == 0)
1010 return NULL;
1011
1012 if (!(m = malloc(sizeof(struct member))))
1013 return NULL;
1014
1015 if ((p = strchr(s, ':')))
1016 {
1017 *p = '\0';
1018 m->name = ++p;
1019 if (!strcasecmp("user", s))
1020 m->type = M_USER;
1021 else if (!strcasecmp("list", s))
1022 m->type = M_LIST;
1023 else if (!strcasecmp("string", s))
1024 m->type = M_STRING;
1025 else if (!strcasecmp("kerberos", s))
1026 m->type = M_KERBEROS;
1027 else
1028 {
1029 m->type = M_ANY;
1030 *(--p) = ':';
1031 m->name = s;
2d7360ca 1032 }
7ac48069 1033 m->name = strdup(m->name);
5eaef520 1034 }
1035 else
1036 {
7ac48069 1037 m->name = strdup(s);
5eaef520 1038 m->type = M_ANY;
2d7360ca 1039 }
5eaef520 1040 return m;
2d7360ca 1041}
1042
1043
5eaef520 1044/*
1045 * This routine two compares members by the following rules:
1046 * 1. A USER is less than a LIST
1047 * 2. A LIST is less than a STRING
1048 * 3. If two members are of the same type, the one alphabetically first
1049 * is less than the other
1050 * It returs < 0 if the first member is less, 0 if they are identical, and
1051 * > 0 if the second member is less (the first member is greater).
1052 */
b5b167d6 1053
7ac48069 1054int membercmp(const void *mem1, const void *mem2)
2d7360ca 1055{
7ac48069 1056 const struct member *m1 = mem1, *m2 = mem2;
1057
5eaef520 1058 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1059 return strcmp(m1->name, m2->name);
1060 else
1061 return m1->type - m2->type;
2d7360ca 1062}
b5b167d6 1063
1064
5eaef520 1065int sq_count_elts(struct save_queue *q)
b5b167d6 1066{
5eaef520 1067 char *foo;
1068 int count;
b5b167d6 1069
5eaef520 1070 count = 0;
1071 while (sq_get_data(q, &foo))
1072 count++;
1073 return count;
b5b167d6 1074}
This page took 0.252431 seconds and 5 git commands to generate.