]> andersk Git - moira.git/blob - clients/blanche/blanche.c
warn if user tries to create/rename a list to a username
[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   /* check for username/listname clash */
312   if (createflag || (setinfo && newname && strcmp(newname, listname)))
313     {
314       status = mr_query("get_user_account_by_login", 1,
315                         createflag ? &listname : &newname,
316                         NULL, NULL);
317       if (status != MR_NO_MATCH)
318         fprintf(stderr, "WARNING: A user by that name already exists.\n");
319     }
320
321   /* create if needed */
322   if (createflag)
323     {
324       char *argv[10];
325
326       argv[0] = listname;
327       argv[1] = (active == 0) ? "0" : "1";
328       argv[2] = (public == 1) ? "1" : "0";
329       argv[3] = (hidden == 1) ? "1" : "0";
330       argv[4] = (maillist == 0) ? "0" : "1";
331       argv[5] = (grouplist == 1) ? "1" : "0";
332       argv[6] = UNIQUE_GID;
333       argv[9] = desc ? desc : "none";
334
335       if (owner)
336         {
337           argv[8] = owner->name;
338           switch (owner->type)
339             {
340             case M_ANY:
341             case M_USER:
342               argv[7] = "USER";
343               status = mr_query("add_list", 10, argv, NULL, NULL);
344               if (owner->type != M_ANY || status != MR_USER)
345                 break;
346
347             case M_LIST:
348               argv[7] = "LIST";
349               status = mr_query("add_list", 10, argv, NULL, NULL);
350               break;
351
352             case M_KERBEROS:
353               argv[7] = "KERBEROS";
354               status = mr_query("add_list", 10, argv, NULL, NULL);
355               break;
356             }
357         }
358       else
359         {
360           argv[7] = "USER";
361           argv[8] = getenv("USER");
362
363           status = mr_query("add_list", 10, argv, NULL, NULL);
364         }
365
366       if (status)
367         {
368           com_err(whoami, status, "while creating list.");
369           exit(1);
370         }
371     }
372   else if (setinfo)
373     {
374       char *argv[11];
375
376       status = mr_query("get_list_info", 1, &listname,
377                         save_list_info, argv);
378       if (status)
379         {
380           com_err(whoami, status, "while getting list information");
381           exit(1);
382         }
383
384       argv[0] = listname;
385       if (newname)
386         argv[1] = newname;
387       if (active != -1)
388         argv[2] = active ? "1" : "0";
389       if (public != -1)
390         argv[3] = public ? "1" : "0";
391       if (hidden != -1)
392         argv[4] = hidden ? "1" : "0";
393       if (maillist != -1)
394         argv[5] = maillist ? "1" : "0";
395       if (grouplist != -1)
396         argv[6] = grouplist ? "1" : "0";
397       if (desc)
398         argv[10] = desc;
399
400       if (owner)
401         {
402           argv[9] = owner->name;
403           switch (owner->type)
404             {
405             case M_ANY:
406             case M_USER:
407               argv[8] = "USER";
408               status = mr_query("update_list", 11, argv, NULL, NULL);
409               if (owner->type != M_ANY || status != MR_USER)
410                 break;
411
412             case M_LIST:
413               argv[8] = "LIST";
414               status = mr_query("update_list", 11, argv, NULL, NULL);
415               break;
416
417             case M_KERBEROS:
418               argv[8] = "KERBEROS";
419               status = mr_query("update_list", 11, argv, NULL, NULL);
420               break;
421             }
422         }
423       else
424         status = mr_query("update_list", 11, argv, NULL, NULL);
425
426       if (status)
427         com_err(whoami, status, "while updating list.");
428       else if (newname)
429         listname = newname;
430     }
431
432   /* display list info if requested to */
433   if (infoflg)
434     {
435       status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
436       if (status)
437         com_err(whoami, status, "while getting list information");
438       if (verbose && !memberflg)
439         {
440           status = mr_query("count_members_of_list", 1, &listname,
441                             show_list_count, NULL);
442           if (status)
443             com_err(whoami, status, "while getting list count");
444         }
445     }
446
447   /* if we're synchronizing to a file, we need to:
448    *  get the current members of the list
449    *    for each member of the sync file
450    *       if they are on the list, remove them from the in-memory copy
451    *       if they're not on the list, add them to add-list
452    *    if anyone is left on the in-memory copy, put them on the delete-list
453    * lastly, reset memberlist so we can use it again later
454    */
455   if (syncflg)
456     {
457       status = mr_query("get_members_of_list", 1, &listname,
458                         get_list_members, memberlist);
459       if (status)
460         {
461           com_err(whoami, status, "getting members of list %s", listname);
462           exit(2);
463         }
464       while (sq_get_data(synclist, &memberstruct))
465         {
466           struct save_queue *q;
467           int removed = 0;
468
469           for (q = memberlist->q_next; q != memberlist; q = q->q_next)
470             {
471               if (membercmp(q->q_data, memberstruct) == 0)
472                 {
473                   q->q_prev->q_next = q->q_next;
474                   q->q_next->q_prev = q->q_prev;
475                   removed++;
476                   break;
477                 }
478             }
479           if (!removed)
480             sq_save_data(addlist, memberstruct);
481         }
482       while (sq_get_data(memberlist, &memberstruct))
483         sq_save_data(dellist, memberstruct);
484       sq_destroy(memberlist);
485       memberlist = sq_create();
486     }
487
488   /* Process the add list */
489   while (sq_get_data(addlist, &memberstruct))
490     {
491       /* canonicalize string if necessary */
492       if (memberstruct->type == M_STRING &&
493           (p = strchr(memberstruct->name, '@')))
494         {
495           char *host = canonicalize_hostname(strdup(++p));
496           static char **mailhubs = NULL;
497           char *argv[4];
498           int i;
499
500           if (!mailhubs)
501             {
502               argv[0] = "mailhub";
503               argv[1] = "TYPE";
504               argv[2] = "*";
505               mailhubs = malloc(sizeof(char *));
506               mailhubs[0] = NULL;
507               status = mr_query("get_alias", 3, argv, collect,
508                                 &mailhubs);
509               if (status != MR_SUCCESS && status != MR_NO_MATCH)
510                 {
511                   com_err(whoami, status,
512                           " while reading list of MAILHUB servers");
513                   mailhubs[0] = NULL;
514                 }
515             }
516           for (i = 0; (p = mailhubs[i]); i++)
517             {
518               if (!strcasecmp(p, host))
519                 {
520                   host = strdup(memberstruct->name);
521                   *(strchr(memberstruct->name, '@')) = 0;
522                   memberstruct->type = M_ANY;
523                   fprintf(stderr, "Warning: \"STRING:%s\" converted to "
524                           "\"%s\" because it is a local name.\n",
525                           host, memberstruct->name);
526                   break;
527                 }
528             }
529           free(host);
530         }
531       /* now continue adding member */
532       membervec[0] = listname;
533       membervec[2] = memberstruct->name;
534       if (verbose)
535         {
536           printf("Adding member ");
537           show_list_member(memberstruct);
538         }
539       switch (memberstruct->type)
540         {
541         case M_ANY:
542         case M_USER:
543           membervec[1] = "USER";
544           status = mr_query("add_member_to_list", 3, membervec, NULL, NULL);
545           if (status == MR_SUCCESS)
546             break;
547           else if (status != MR_USER || memberstruct->type != M_ANY)
548             {
549               com_err(whoami, status, "while adding member %s to %s",
550                       memberstruct->name, listname);
551               success = 0;
552               break;
553             }
554         case M_LIST:
555           membervec[1] = "LIST";
556           status = mr_query("add_member_to_list", 3, membervec,
557                             NULL, NULL);
558           if (status == MR_SUCCESS)
559             {
560               if (!strcmp(membervec[0], getenv("USER")))
561                 {
562                   fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
563                           "to list \"%s\".\n", membervec[2], membervec[0]);
564                   fprintf(stderr, "If you meant to add yourself to the list "
565                           "\"%s\", type:\n", membervec[2]);
566                   fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
567                           membervec[0], membervec[2]);
568                   fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
569                           "that list)\n", membervec[2], membervec[0]);
570                 }
571               break;
572             }
573           else if (status != MR_LIST || memberstruct->type != M_ANY)
574             {
575               com_err(whoami, status, "while adding member %s to %s",
576                       memberstruct->name, listname);
577               success = 0;
578               break;
579             }
580         case M_STRING:
581           if (memberstruct->type == M_ANY &&
582               !strchr(memberstruct->name, '@') &&
583               !strchr(memberstruct->name, '!') &&
584               !strchr(memberstruct->name, '%'))
585             {
586               /* if user is trying to add something which isn't a
587                  remote string, or a list, or a user, and didn't
588                  explicitly specify `STRING:', it's probably a typo */
589               com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
590                       memberstruct->name, listname);
591               success = 0;
592               break;
593             }
594
595           membervec[1] = "STRING";
596           status = mr_query("add_member_to_list", 3, membervec,
597                             NULL, NULL);
598           if (status != MR_SUCCESS)
599             {
600               com_err(whoami, status, "while adding member %s to %s",
601                       memberstruct->name, listname);
602               success = 0;
603             }
604           break;
605         case M_KERBEROS:
606           membervec[1] = "KERBEROS";
607           status = mr_query("add_member_to_list", 3, membervec,
608                             NULL, NULL);
609           if (status != MR_SUCCESS)
610             {
611               com_err(whoami, status, "while adding member %s to %s",
612                       memberstruct->name, listname);
613               success = 0;
614             }
615         }
616     }
617
618   /* Process the delete list */
619   while (sq_get_data(dellist, &memberstruct))
620     {
621       membervec[0] = listname;
622       membervec[2] = memberstruct->name;
623       if (verbose)
624         {
625           printf("Deleting member ");
626           show_list_member(memberstruct);
627         }
628       switch (memberstruct->type)
629         {
630         case M_ANY:
631         case M_USER:
632           membervec[1] = "USER";
633           status = mr_query("delete_member_from_list", 3, membervec,
634                             NULL, NULL);
635           if (status == MR_SUCCESS)
636             break;
637           else if ((status != MR_USER && status != MR_NO_MATCH) ||
638                    memberstruct->type != M_ANY)
639             {
640               com_err(whoami, status, "while deleting member %s from %s",
641                       memberstruct->name, listname);
642               success = 0;
643               break;
644             }
645         case M_LIST:
646           membervec[1] = "LIST";
647           status = mr_query("delete_member_from_list", 3, membervec,
648                             NULL, NULL);
649           if (status == MR_SUCCESS)
650             break;
651           else if ((status != MR_LIST && status != MR_NO_MATCH) ||
652                    memberstruct->type != M_ANY)
653             {
654               if (status == MR_PERM && memberstruct->type == M_ANY &&
655                   !strcmp(membervec[2], getenv("USER")))
656                 {
657                   /* M_ANY means we've fallen through from the user
658                    * case. The user is trying to remove himself from
659                    * a list, but we got MR_USER or MR_NO_MATCH above,
660                    * meaning he's not really on it, and we got MR_PERM
661                    * when trying to remove LIST:$USER because he's not
662                    * on the acl. That error is useless, so return
663                    * MR_NO_MATCH instead. However, this will generate the
664                    * wrong error if the user was trying to remove the list
665                    * with his username from a list he doesn't administrate
666                    * without explicitly specifying "list:".
667                    */
668                   status = MR_NO_MATCH;
669                 }
670               com_err(whoami, status, "while deleting member %s from %s",
671                       memberstruct->name, listname);
672               success = 0;
673               break;
674             }
675         case M_STRING:
676           membervec[1] = "STRING";
677           status = mr_query("delete_member_from_list", 3, membervec,
678                             NULL, NULL);
679           if (status == MR_STRING && memberstruct->type == M_ANY)
680             {
681               com_err(whoami, 0, " Unable to find member %s to delete from %s",
682                       memberstruct->name, listname);
683               success = 0;
684               if (!strcmp(membervec[0], getenv("USER")))
685                 {
686                   fprintf(stderr, "(If you were trying to remove yourself "
687                           "from the list \"%s\",\n", membervec[2]);
688                   fprintf(stderr, "the correct command is \"blanche %s -d "
689                           "%s\".)\n", membervec[2], membervec[0]);
690                 }
691             }
692           else if (status != MR_SUCCESS)
693             {
694               com_err(whoami, status, "while deleting member %s from %s",
695                       memberstruct->name, listname);
696               success = 0;
697             }
698           break;
699         case M_KERBEROS:
700           membervec[1] = "KERBEROS";
701           status = mr_query("delete_member_from_list", 3, membervec,
702                             NULL, NULL);
703           if (status != MR_SUCCESS)
704             {
705               com_err(whoami, status, "while deleting member %s from %s",
706                       memberstruct->name, listname);
707               success = 0;
708             }
709         }
710     }
711
712   /* Display the members of the list now, if requested */
713   if (memberflg)
714     {
715       if (recursflg)
716         recursive_display_list_members();
717       else
718         {
719           status = mr_query("get_members_of_list", 1, &listname,
720                             get_list_members, memberlist);
721           if (status)
722             com_err(whoami, status, "while getting members of list %s",
723                     listname);
724           while (sq_get_data(memberlist, &memberstruct))
725             show_list_member(memberstruct);
726         }
727     }
728
729   /* We're done! */
730   mr_disconnect();
731   exit(success ? 0 : 1);
732 }
733
734 void usage(char **argv)
735 {
736   fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
737   fprintf(stderr, "Options are\n");
738   fprintf(stderr, "  %-39s%-39s\n", "-v  | -verbose",
739           "-C  | -create");
740   fprintf(stderr, "  %-39s%-39s\n", "-m  | -members",
741           "-R  | -rename newname");
742   fprintf(stderr, "  %-39s%-39s\n", "-u  | -users",
743           "-P  | -public");
744   fprintf(stderr, "  %-39s%-39s\n", "-l  | -lists",
745           "-NP | -private");
746   fprintf(stderr, "  %-39s%-39s\n", "-s  | -strings",
747           "-A  | -active");
748   fprintf(stderr, "  %-39s%-39s\n", "-k  | -kerberos",
749           "-I  | -inactive");
750   fprintf(stderr, "  %-39s%-39s\n", "-i  | -info",
751           "-V  | -visible");
752   fprintf(stderr, "  %-39s%-39s\n", "-r  | -recursive",
753           "-H  | -hidden");
754   fprintf(stderr, "  %-39s%-39s\n", "-a  | -add member",
755           "-M  | -mail");
756   fprintf(stderr, "  %-39s%-39s\n", "-d  | -delete member",
757           "-NM | -notmail");
758   fprintf(stderr, "  %-39s%-39s\n", "-al | -addlist filename",
759           "-G  | -group");
760   fprintf(stderr, "  %-39s%-39s\n", "-dl | -deletelist filename",
761           "-NG | -notgroup");
762   fprintf(stderr, "  %-39s%-39s\n", "-f  | -file filename",
763           "-D  | -desc description");
764   fprintf(stderr, "  %-39s%-39s\n", "-n  | -noauth",
765           "-O  | -owner owner");
766   fprintf(stderr, "  %-39s%-39s\n", "-db | -database host[:port]",
767           "");
768   exit(1);
769 }
770
771
772 /* Display the members stored in the queue */
773
774 void show_list_member(struct member *memberstruct)
775 {
776   char *s = "";
777
778   switch (memberstruct->type)
779     {
780     case M_USER:
781       if (!showusers)
782         return;
783       s = "USER";
784       break;
785     case M_LIST:
786       if (!showlists)
787         return;
788       s = "LIST";
789       break;
790     case M_STRING:
791       if (!showstrings)
792         return;
793       s = "STRING";
794       break;
795     case M_KERBEROS:
796       if (!showkerberos)
797         return;
798       s = "KERBEROS";
799       break;
800     case M_ANY:
801       printf("%s\n", memberstruct->name);
802       return;
803     }
804
805   if (verbose)
806     printf("%s:%s\n", s, memberstruct->name);
807   else
808     {
809       if (memberstruct->type == M_LIST)
810         printf("LIST:%s\n", memberstruct->name);
811       else if (memberstruct->type == M_KERBEROS)
812         printf("KERBEROS:%s\n", memberstruct->name);
813       else if (memberstruct->type == M_STRING &&
814                !strchr(memberstruct->name, '@'))
815         printf("STRING:%s\n", memberstruct->name);
816       else
817         printf("%s\n", memberstruct->name);
818     }
819 }
820
821
822 /* Show the retrieved information about a list */
823
824 int show_list_info(int argc, char **argv, void *hint)
825 {
826   printf("List: %s\n", argv[0]);
827   printf("Description: %s\n", argv[9]);
828   printf("Flags: %s, %s, and %s\n",
829          atoi(argv[1]) ? "active" : "inactive",
830          atoi(argv[2]) ? "public" : "private",
831          atoi(argv[3]) ? "hidden" : "visible");
832   printf("%s is %sa maillist and is %sa group", argv[0],
833          atoi(argv[4]) ? "" : "not ",
834          atoi(argv[5]) ? "" : "not ");
835   if (atoi(argv[5]))
836     printf(" with GID %d\n", atoi(argv[6]));
837   else
838     printf("\n");
839   printf("Owner: %s %s\n", argv[7], argv[8]);
840   printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
841   return MR_CONT;
842 }
843
844
845 /* Copy retrieved information about a list into a new argv */
846
847 int save_list_info(int argc, char **argv, void *hint)
848 {
849   char **nargv = hint;
850
851   for (argc = 0; argc < 10; argc++)
852     nargv[argc + 1] = strdup(argv[argc]);
853   return MR_CONT;
854 }
855
856 /* Show the retrieve list member count */
857
858 int show_list_count(int argc, char **argv, void *hint)
859 {
860   printf("Members: %s\n", argv[0]);
861   return MR_CONT;
862 }
863
864
865 /* Recursively find all of the members of listname, and then display them */
866
867 void recursive_display_list_members(void)
868 {
869   int status, count, savecount;
870   struct save_queue *lists, *members;
871   struct member *m, *m1, *data;
872
873   lists = sq_create();
874   members = sq_create();
875   m = malloc(sizeof(struct member));
876   m->type = M_LIST;
877   m->name = listname;
878   sq_save_data(lists, m);
879
880   while (sq_get_data(lists, &m))
881     {
882       sq_destroy(memberlist);
883       memberlist = sq_create();
884       status = mr_query("get_members_of_list", 1, &(m->name),
885                         get_list_members, memberlist);
886       if (status)
887         com_err(whoami, status, "while getting members of list %s", m->name);
888       while (sq_get_data(memberlist, &m1))
889         {
890           if (m1->type == M_LIST)
891             unique_add_member(lists, m1);
892           else
893             unique_add_member(members, m1);
894         }
895     }
896   savecount = count = sq_count_elts(members);
897   data = malloc(count * sizeof(struct member));
898   count = 0;
899   while (sq_get_data(members, &m))
900     memcpy(&data[count++], m, sizeof(struct member));
901   qsort(data, count, sizeof(struct member), membercmp);
902   for (count = 0; count < savecount; count++)
903     show_list_member(&data[count]);
904 }
905
906
907 /* add a struct member to a queue if that member isn't already there. */
908
909 void unique_add_member(struct save_queue *q, struct member *m)
910 {
911   struct save_queue *qp;
912
913   for (qp = q->q_next; qp != q; qp = qp->q_next)
914     {
915       if (!membercmp(qp->q_data, m))
916         return;
917     }
918   sq_save_data(q, m);
919 }
920
921
922 /* Collect the retrieved members of the list */
923
924 int get_list_members(int argc, char **argv, void *sq)
925 {
926   struct save_queue *q = sq;
927   struct member *m;
928
929   m = malloc(sizeof(struct member));
930   switch (argv[0][0])
931     {
932     case 'U':
933       m->type = M_USER;
934       break;
935     case 'L':
936       m->type = M_LIST;
937       break;
938     case 'S':
939       m->type = M_STRING;
940       break;
941     case 'K':
942       m->type = M_KERBEROS;
943       break;
944     }
945   m->name = strdup(argv[1]);
946   sq_save_data(q, m);
947   return MR_CONT;
948 }
949
950
951 /* Open file, parse members from file, and put them on the specified queue */
952 void get_members_from_file(char *filename, struct save_queue *queue)
953 {
954   FILE *in;
955   char buf[BUFSIZ];
956   struct member *memberstruct;
957
958   if (!strcmp(filename, "-"))
959     in = stdin;
960   else
961     {
962       in = fopen(filename, "r");
963       if (!in)
964         {
965           com_err(whoami, errno, "while opening %s for input", filename);
966           exit(2);
967         }
968     }
969
970   while (fgets(buf, BUFSIZ, in))
971     {
972       if ((memberstruct = parse_member(buf)))
973         sq_save_data(queue, memberstruct);
974     }
975   if (!feof(in))
976     {
977       com_err(whoami, errno, "while reading from %s", filename);
978       exit(2);
979     }
980 }
981
982
983 /* Collect the possible expansions of the alias MAILHUB */
984
985 int collect(int argc, char **argv, void *l)
986 {
987   char ***list = l;
988   int i;
989
990   for (i = 0; (*list)[i]; i++)
991     ;
992   *list = realloc(*list, (i + 2) * sizeof(char *));
993   (*list)[i] = strdup(argv[2]);
994   (*list)[i + 1] = NULL;
995   return MR_CONT;
996 }
997
998
999 /* Parse a line of input, fetching a member.  NULL is returned if a member
1000  * is not found.  ';' is a comment character.
1001  */
1002
1003 struct member *parse_member(char *s)
1004 {
1005   struct member *m;
1006   char *p, *lastchar;
1007
1008   while (*s && isspace(*s))
1009     s++;
1010   lastchar = p = s;
1011   while (*p && *p != '\n' && *p != ';')
1012     {
1013       if (isprint(*p) && !isspace(*p))
1014         lastchar = p++;
1015       else
1016         p++;
1017     }
1018   lastchar++;
1019   *lastchar = '\0';
1020   if (p == s || strlen(s) == 0)
1021     return NULL;
1022
1023   if (!(m = malloc(sizeof(struct member))))
1024     return NULL;
1025
1026   if ((p = strchr(s, ':')))
1027     {
1028       *p = '\0';
1029       m->name = ++p;
1030       if (!strcasecmp("user", s))
1031         m->type = M_USER;
1032       else if (!strcasecmp("list", s))
1033         m->type = M_LIST;
1034       else if (!strcasecmp("string", s))
1035         m->type = M_STRING;
1036       else if (!strcasecmp("kerberos", s))
1037         m->type = M_KERBEROS;
1038       else
1039         {
1040           m->type = M_ANY;
1041           *(--p) = ':';
1042           m->name = s;
1043         }
1044       m->name = strdup(m->name);
1045     }
1046   else
1047     {
1048       m->name = strdup(s);
1049       m->type = M_ANY;
1050     }
1051   return m;
1052 }
1053
1054
1055 /*
1056  * This routine two compares members by the following rules:
1057  * 1.  A USER is less than a LIST
1058  * 2.  A LIST is less than a STRING
1059  * 3.  If two members are of the same type, the one alphabetically first
1060  *     is less than the other
1061  * It returs < 0 if the first member is less, 0 if they are identical, and
1062  * > 0 if the second member is less (the first member is greater).
1063  */
1064
1065 int membercmp(const void *mem1, const void *mem2)
1066 {
1067   const struct member *m1 = mem1, *m2 = mem2;
1068
1069   if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1070     return strcmp(m1->name, m2->name);
1071   else
1072     return m1->type - m2->type;
1073 }
1074
1075
1076 int sq_count_elts(struct save_queue *q)
1077 {
1078   char *foo;
1079   int count;
1080
1081   count = 0;
1082   while (sq_get_data(q, &foo))
1083     count++;
1084   return count;
1085 }
This page took 0.291569 seconds and 5 git commands to generate.