3 * Command line oriented SMS List tool.
5 * by Mark Rosenstein, September 1988.
7 * Copyright 1989 by the Massachusetts Institute of Technology.
9 * (c) Copyright 1988 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, please see the file
14 /* ### Aren't there a lot of sq abstraction barrier violations here?
15 Do we need to improve the support for queue operations? */
17 #include <mit-copyright.h>
24 static char smslist_rcsid[] = "$Header$";
33 /* It is important to membercmp that M_USER < M_LIST < M_STRING */
39 /* argument parsing macro */
40 #define argis(a,b) ((strcmp(*arg+1, a) == 0) || (strcmp(*arg+1, b) == 0))
42 /* flags from command line */
43 int infoflg, verbose, syncflg, memberflg, recursflg, debugflg;
45 /* various member lists */
46 struct save_queue *addlist, *dellist, *memberlist, *synclist;
48 char *listname, *whoami;
53 int show_list_info(), show_list_count(), get_list_members(), scream();
54 int show_list_members();
55 struct member *parse_member();
66 struct member *memberstruct;
68 /* clear all flags & lists */
69 infoflg = verbose = syncflg = memberflg = debugflg = recursflg = 0;
71 addlist = sq_create();
72 dellist = sq_create();
73 memberlist = sq_create();
74 synclist = sq_create();
77 /* parse args, building addlist, dellist, & synclist */
78 while (++arg - argv < argc) {
81 if (argis("m", "members"))
83 else if (argis("D", "debug"))
85 else if (argis("i","information"))
87 else if (argis("v","verbose"))
89 else if (argis("r","recursive"))
91 else if (argis("a","add"))
92 if (arg - argv < argc - 1) {
94 if (memberstruct = parse_member(*arg))
95 sq_save_data(addlist, memberstruct);
98 else if (argis("d","delete"))
99 if (arg - argv < argc - 1) {
101 if (memberstruct = parse_member(*arg))
102 sq_save_data(dellist, memberstruct);
105 else if (argis("f","file"))
106 if (arg - argv < argc - 1) {
112 if (!strcmp(*arg, "-"))
115 in = fopen(*arg, "r");
117 com_err(whoami, errno,
118 " while opening %s for input", *arg);
122 while (fgets(buf, BUFSIZ, in))
123 if (memberstruct = parse_member(buf))
124 sq_save_data(synclist, memberstruct);
126 com_err(whoami, errno, " while reading from %s", *arg);
132 else if (listname == NULL)
137 if (listname == NULL)
140 /* if no other options specified, turn on list members flag */
141 if (!(infoflg || syncflg ||
142 addlist->q_next != addlist || dellist->q_next != dellist))
146 if (status = sms_connect(SMS_SERVER)) {
147 com_err(whoami, status, " unable to connect to SMS");
150 if (status = sms_auth("blanche")) {
151 com_err(whoami, status, " unable to authenticate to SMS");
155 /* display list info if requested to */
157 status = sms_query("get_list_info", 1, &listname, show_list_info,NULL);
159 com_err(whoami, status, " while getting list information");
160 if (verbose && !memberflg) {
161 status = sms_query("count_members_of_list", 1, &listname,
162 show_list_count, NULL);
164 com_err(whoami, status, " while getting list count");
168 /* if we're synchronizing to a file, we need to:
169 * get the current members of the list
170 * for each member of the sync file
171 * if they are on the list, remove them from the in-memory copy
172 * if they're not on the list, add them to add-list
173 * if anyone is left on the in-memory copy, put them on the delete-list
174 * lastly, reset memberlist so we can use it again later
177 status = sms_query("get_members_of_list", 1, &listname,
178 get_list_members, (char *)memberlist);
180 com_err(whoami, status, " getting members of list %s", listname);
181 while (sq_get_data(synclist, &memberstruct)) {
182 struct save_queue *q;
185 for (q = memberlist->q_next; q != memberlist; q = q->q_next) {
186 if (membercmp(q->q_data, memberstruct) == 0) {
187 q->q_prev->q_next = q->q_next;
188 q->q_next->q_prev = q->q_prev;
194 sq_save_data(addlist, memberstruct);
196 while (sq_get_data(memberlist, &memberstruct))
197 sq_save_data(dellist, memberstruct);
198 sq_destroy(memberlist);
199 memberlist = sq_create();
202 /* Process the add list */
203 while (sq_get_data(addlist, &memberstruct)) {
204 membervec[0] = listname;
205 membervec[2] = memberstruct->name;
206 if (verbose && syncflg) {
207 printf("Adding member ");
208 show_list_member(memberstruct);
210 switch (memberstruct->type) {
213 membervec[1] = "USER";
214 status = sms_query("add_member_to_list", 3, membervec, scream, NULL);
215 if (status == SMS_SUCCESS)
217 else if (status != SMS_USER || memberstruct->type != M_ANY) {
218 com_err(whoami, status, " while adding member %s to %s",
219 memberstruct->name, listname);
223 membervec[1] = "LIST";
224 status = sms_query("add_member_to_list", 3, membervec,
226 if (status == SMS_SUCCESS)
228 else if (status != SMS_LIST || memberstruct->type != M_ANY) {
229 com_err(whoami, status, " while adding member %s to %s",
230 memberstruct->name, listname);
234 membervec[1] = "STRING";
235 status = sms_query("add_member_to_list", 3, membervec,
237 if (status != SMS_SUCCESS)
238 com_err(whoami, status, " while adding member %s to %s",
239 memberstruct->name, listname);
243 /* Process the delete list */
244 while (sq_get_data(dellist, &memberstruct)) {
245 membervec[0] = listname;
246 membervec[2] = memberstruct->name;
247 if (verbose && syncflg) {
248 printf("Deleting member ");
249 show_list_member(memberstruct);
251 switch (memberstruct->type) {
254 membervec[1] = "USER";
255 status = sms_query("delete_member_from_list", 3, membervec,
257 if (status == SMS_SUCCESS)
259 else if ((status != SMS_USER && status != SMS_NO_MATCH) ||
260 memberstruct->type != M_ANY) {
261 com_err(whoami, status, " while deleteing member %s from %s",
262 memberstruct->name, listname);
266 membervec[1] = "LIST";
267 status = sms_query("delete_member_from_list", 3, membervec,
269 if (status == SMS_SUCCESS)
271 else if ((status != SMS_LIST && status != SMS_NO_MATCH) ||
272 memberstruct->type != M_ANY) {
273 com_err(whoami, status, " while deleteing member %s from %s",
274 memberstruct->name, listname);
278 membervec[1] = "STRING";
279 status = sms_query("delete_member_from_list", 3, membervec,
281 if (status == SMS_STRING && memberstruct->type == M_ANY)
282 com_err(whoami, 0, "Unable to find member %s to delete from %s",
283 memberstruct->name, listname);
284 else if (status != SMS_SUCCESS)
285 com_err(whoami, status, " while deleteing member %s from %s",
286 memberstruct->name, listname);
290 /* Display the members of the list now, if requested */
293 recursive_display_list_members();
295 status = sms_query("get_members_of_list", 1, &listname,
296 get_list_members, (char *)memberlist);
298 com_err(whoami, status, " while getting members of list %s",
300 while (sq_get_data(memberlist, &memberstruct))
301 show_list_member(memberstruct);
313 fprintf(stderr, "Usage: %s [options] listname [options]\n",argv[0]);
314 fprintf(stderr, "Options are\n");
315 fprintf(stderr, " -v | -verbose\n");
316 fprintf(stderr, " -m | -members\n");
317 fprintf(stderr, " -i | -info\n");
318 fprintf(stderr, " -r | -recursive\n");
319 fprintf(stderr, " -a | -add member\n");
320 fprintf(stderr, " -d | -delete member\n");
321 fprintf(stderr, " -f | -file filename\n");
322 fprintf(stderr, " -D | -debug\n");
327 /* Display the members stored in the queue */
329 show_list_member(memberstruct)
330 struct member *memberstruct;
334 switch (memberstruct->type) {
345 printf("%s\n", memberstruct->name);
348 printf("%s:%s\n", s, memberstruct->name);
350 if (memberstruct->type == M_LIST)
351 printf("LIST:%s\n", memberstruct->name);
352 else if (memberstruct->type == M_STRING &&
353 !index(memberstruct->name, '@'))
354 printf("STRING:%s\n", memberstruct->name);
356 printf("%s\n", memberstruct->name);
361 /* Show the retrieved information about a list */
363 show_list_info(argc, argv, hint)
368 printf("List: %s\n", argv[0]);
369 printf("Description: %s\n", argv[9]);
370 printf("Flags: %s, %s, and %s\n",
371 atoi(argv[1]) ? "active" : "inactive",
372 atoi(argv[2]) ? "public" : "private",
373 atoi(argv[3]) ? "hidden" : "visible");
374 printf("%s is %sa maillist and is %sa group", argv[0],
375 atoi(argv[4]) ? "" : "not ",
376 atoi(argv[5]) ? "" : "not ");
378 printf(" with GID %d\n", atoi(argv[6]));
381 printf("Owner: %s %s\n", argv[7], argv[8]);
382 printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
387 /* Show the retrieve list member count */
389 show_list_count(argc, argv, hint)
394 printf("Members: %s\n", argv[0]);
398 /* Recursively find all of the members of listname, and then display them */
400 recursive_display_list_members()
402 int status, count, savecount;
403 struct save_queue *lists, *members;
404 struct member *m, *m1, *data;
407 members = sq_create();
408 m = (struct member *) malloc(sizeof(struct member));
411 sq_save_data(lists, m);
413 while (sq_get_data(lists, &m)) {
414 sq_destroy(memberlist);
415 memberlist = sq_create();
417 fprintf(stderr, "Fetching members of %s\n", m->name);
418 status = sms_query("get_members_of_list", 1, &(m->name),
419 get_list_members, (char *)memberlist);
421 com_err(whoami, status, " while getting members of list %s", m->name);
422 while (sq_get_data(memberlist, &m1)) {
423 if (m1->type == M_LIST)
424 unique_add_member(lists, m1);
426 unique_add_member(members, m1);
429 savecount = count = sq_count_elts(members);
430 data = (struct member *) malloc(count * sizeof(struct member));
432 while (sq_get_data(members, &m))
433 bcopy(m, &data[count++], sizeof(struct member));
434 qsort(data, count, sizeof(struct member), membercmp);
435 for (count = 0; count < savecount; count++) {
436 show_list_member(&data[count]);
441 /* add a struct member to a queue if that member isn't already there. */
443 unique_add_member(q, m)
444 struct save_queue *q;
447 struct save_queue *qp;
449 for (qp = q->q_next; qp != q; qp = qp->q_next) {
450 if (!membercmp(qp->q_data, m))
457 /* Collect the retrieved members of the list */
459 get_list_members(argc, argv, q)
462 struct save_queue *q;
466 m = (struct member *) malloc(sizeof(struct member));
467 switch (argv[0][0]) {
478 m->name = strsave(argv[1]);
484 /* Called only if a query returns a value that we weren't expecting */
488 fprintf(stderr, "Programmer botch\n");
493 /* Parse a line of input, fetching a member. NULL is returned if a member
494 * is not found. Only the first token on the line is parsed. ';' is a
498 struct member *parse_member(s)
501 register struct member *m;
504 while (*s && isspace(*s))
507 while (*p && isprint(*p) && !isspace(*p) && *p != ';')
510 if (p == s || strlen(s) == 0)
513 if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
516 if (p = index(s, ':')) {
519 if (!strcasecmp("user", s))
521 else if (!strcasecmp("list", s))
523 else if (!strcasecmp("string", s))
530 m->name = strsave(m->name);
533 m->name = strsave(s);
534 if (index(s, '@') || index(s, '!') || index(s, '%'))
543 * This routine two compares members by the following rules:
544 * 1. A USER is less than a LIST
545 * 2. A LIST is less than a STRING
546 * 3. If two members are of the same type, the one alphabetically first
547 * is less than the other
548 * It returs < 0 if the first member is less, 0 if they are identical, and
549 * > 0 if the second member is less (the first member is greater).
552 int membercmp(m1, m2)
553 struct member *m1, *m2;
555 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
556 return(strcmp(m1->name, m2->name));
558 return(m1->type - m2->type);
563 struct save_queue *q;
569 while (sq_get_data(q, &foo))