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