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 /* member types: ### This should be an enumerated type ?
34 It is important to membercmp that M_USER < M_LIST < M_STRING */
40 /* argument parsing macro */
41 #define argis(a,b) ((strcmp(*arg+1, a) == 0) || (strcmp(*arg+1, b) == 0))
43 /* flags from command line */
44 int infoflg, verbose, syncflg, memberflg, recursflg, debugflg;
46 /* various member lists */
47 struct save_queue *addlist, *dellist, *memberlist, *synclist;
49 char *listname, *whoami;
54 int show_list_info(), show_list_count(), get_list_members(), scream();
55 int show_list_members();
56 struct member *parse_member();
67 struct member *memberstruct;
69 /* clear all flags & lists */
70 infoflg = verbose = syncflg = memberflg = debugflg = recursflg = 0;
72 addlist = sq_create();
73 dellist = sq_create();
74 memberlist = sq_create();
75 synclist = sq_create();
78 /* parse args, building addlist, dellist, & synclist */
79 while (++arg - argv < argc) {
82 if (argis("m", "members"))
84 else if (argis("D", "debug"))
86 else if (argis("i","information"))
88 else if (argis("v","verbose"))
90 else if (argis("r","recursive"))
92 else if (argis("a","add"))
93 if (arg - argv < argc - 1) {
95 if (memberstruct = parse_member(*arg))
96 sq_save_data(addlist, memberstruct);
99 else if (argis("d","delete"))
100 if (arg - argv < argc - 1) {
102 if (memberstruct = parse_member(*arg))
103 sq_save_data(dellist, memberstruct);
106 else if (argis("f","file"))
107 if (arg - argv < argc - 1) {
113 if (!strcmp(*arg, "-"))
116 in = fopen(*arg, "r");
118 com_err(whoami, errno,
119 " while opening %s for input", *arg);
123 while (fgets(buf, BUFSIZ, in))
124 if (memberstruct = parse_member(buf))
125 sq_save_data(synclist, memberstruct);
127 com_err(whoami, errno, " while reading from %s", *arg);
133 else if (listname == NULL)
138 if (listname == NULL)
141 /* if no other options specified, turn on list members flag */
142 if (!(infoflg || syncflg ||
143 addlist->q_next != addlist || dellist->q_next != dellist))
147 if (status = sms_connect()) {
148 com_err(whoami, status, " unable to connect to SMS");
151 if (status = sms_auth("blanche")) {
152 com_err(whoami, status, " unable to authenticate to SMS");
156 /* display list info if requested to */
158 status = sms_query("get_list_info", 1, &listname, show_list_info,NULL);
160 com_err(whoami, status, " while getting list information");
161 if (verbose && !memberflg) {
162 status = sms_query("count_members_of_list", 1, &listname,
163 show_list_count, NULL);
165 com_err(whoami, status, " while getting list count");
169 /* if we're synchronizing to a file, we need to:
170 * get the current members of the list
171 * for each member of the sync file
172 * if they are on the list, remove them from the in-memory copy
173 * if they're not on the list, add them to add-list
174 * if anyone is left on the in-memory copy, put them on the delete-list
175 * lastly, reset memberlist so we can use it again later
178 status = sms_query("get_members_of_list", 1, &listname,
179 get_list_members, (char *)memberlist);
181 com_err(whoami, status, " while getting members of list");
182 while (sq_get_data(synclist, &memberstruct)) {
183 struct save_queue *q;
186 for (q = memberlist->q_next; q != memberlist; q = q->q_next) {
187 if (membercmp(q->q_data, memberstruct) == 0) {
188 q->q_prev->q_next = q->q_next;
189 q->q_next->q_prev = q->q_prev;
195 sq_save_data(addlist, memberstruct);
197 while (sq_get_data(memberlist, &memberstruct))
198 sq_save_data(dellist, memberstruct);
199 sq_destroy(memberlist);
200 memberlist = sq_create();
203 /* Process the add list */
204 while (sq_get_data(addlist, &memberstruct)) {
205 membervec[0] = listname;
206 membervec[2] = memberstruct->name;
207 switch (memberstruct->type) {
210 membervec[1] = "USER";
211 status = sms_query("add_member_to_list", 3, membervec, scream, NULL);
212 if (status == SMS_SUCCESS)
214 else if (status != SMS_USER || memberstruct->type != M_ANY) {
215 com_err(whoami, status, " while adding member %s to %s",
216 memberstruct->name, listname);
220 membervec[1] = "LIST";
221 status = sms_query("add_member_to_list", 3, membervec,
223 if (status == SMS_SUCCESS)
225 else if (status != SMS_LIST || memberstruct->type != M_ANY) {
226 com_err(whoami, status, " while adding member %s to %s",
227 memberstruct->name, listname);
231 membervec[1] = "STRING";
232 status = sms_query("add_member_to_list", 3, membervec,
234 if (status != SMS_SUCCESS)
235 com_err(whoami, status, " while adding member %s to %s",
236 memberstruct->name, listname);
240 /* Process the delete list */
241 while (sq_get_data(dellist, &memberstruct)) {
242 membervec[0] = listname;
243 membervec[2] = memberstruct->name;
244 switch (memberstruct->type) {
247 membervec[1] = "USER";
248 status = sms_query("delete_member_from_list", 3, membervec,
250 if (status == SMS_SUCCESS)
252 else if ((status != SMS_USER && status != SMS_NO_MATCH) ||
253 memberstruct->type != M_ANY) {
254 com_err(whoami, status, " while deleteing member %s from %s",
255 memberstruct->name, listname);
259 membervec[1] = "LIST";
260 status = sms_query("delete_member_from_list", 3, membervec,
262 if (status == SMS_SUCCESS)
264 else if ((status != SMS_LIST && status != SMS_NO_MATCH) ||
265 memberstruct->type != M_ANY) {
266 com_err(whoami, status, " while deleteing member %s from %s",
267 memberstruct->name, listname);
271 membervec[1] = "STRING";
272 status = sms_query("delete_member_from_list", 3, membervec,
274 if (status == SMS_STRING && memberstruct->type == M_ANY)
275 com_err(whoami, 0, "Unable to find member %s to delete from %s",
276 memberstruct->name, listname);
277 else if (status != SMS_SUCCESS)
278 com_err(whoami, status, " while deleteing member %s from %s",
279 memberstruct->name, listname);
283 /* Display the members of the list now, if requested */
285 display_list_members();
295 fprintf(stderr, "Usage: %s [options] listname [options]\n",argv[0]);
296 fprintf(stderr, "Options are\n");
297 fprintf(stderr, " -v | -verbose\n");
298 fprintf(stderr, " -m | -members\n");
299 fprintf(stderr, " -i | -info\n");
300 fprintf(stderr, " -r | -recursive\n");
301 fprintf(stderr, " -a | -add member\n");
302 fprintf(stderr, " -d | -delete member\n");
303 fprintf(stderr, " -f | -file filename\n");
305 fprintf(stderr, " -D | -debug\n");
311 show_list_members(memberlist)
312 struct sq *memberlist;
314 struct member *memberstruct;
316 while (sq_get_data(memberlist, &memberstruct)) {
319 switch (memberstruct->type) {
330 printf("%s:%s\n", s, memberstruct->name);
332 if (memberstruct->type == M_LIST)
333 printf("LIST:%s\n", memberstruct->name);
334 else if (memberstruct->type == M_STRING &&
335 !index(memberstruct->name, '@'))
336 printf("STRING:%s\n", memberstruct->name);
338 printf("%s\n", memberstruct->name);
343 show_list_info(argc, argv, hint)
348 printf("List: %s\n", argv[0]);
349 printf("Description: %s\n", argv[9]);
350 printf("Flags: %s, %s, and %s\n",
351 atoi(argv[1]) ? "active" : "inactive",
352 atoi(argv[2]) ? "public" : "private",
353 atoi(argv[3]) ? "hidden" : "visible");
354 printf("%s is %sa maillist and is %sa group", argv[0],
355 atoi(argv[4]) ? "" : "not ",
356 atoi(argv[5]) ? "" : "not ");
358 printf(" with GID %d\n", atoi(argv[6]));
361 printf("Owner: %s %s\n", argv[7], argv[8]);
362 printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
367 show_list_count(argc, argv, hint)
372 printf("Members: %s\n", argv[0]);
376 display_list_members()
380 status = sms_query("get_members_of_list", 1, &listname,
381 get_list_members, (char *)memberlist);
383 com_err(whoami, status, " while getting members of list");
385 fprintf(stderr,"%s: The recursive flag is not yet implemented.\n",
387 show_list_members(memberlist);
390 get_list_members(argc, argv, q)
393 struct save_queue *q;
397 m = (struct member *) malloc(sizeof(struct member));
398 switch (argv[0][0]) {
409 m->name = strsave(argv[1]);
417 fprintf(stderr, "Programmer botch\n");
422 struct member *parse_member(s)
425 register struct member *m;
428 while (*s && isspace(*s))
431 while (*p && isprint(*p) && !isspace(*p) && *p != ';')
434 if (p == s || strlen(s) == 0)
437 if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
440 if (p = index(s, ':')) {
443 if (!strcasecmp("user", s))
445 else if (!strcasecmp("list", s))
447 else if (!strcasecmp("string", s))
454 m->name = strsave(m->name);
457 m->name = strsave(s);
458 if (index(s, '@') || index(s, '!') || index(s, '%'))
466 int membercmp(m1, m2)
467 struct member *m1, *m2;
469 * This routine two compares members by the following rules:
470 * 1. A USER is less than a LIST
471 * 2. A LIST is less than a STRING
472 * 3. If two members are of the same type, the one alphabetically first
473 * is less than the other
474 * It returs < 0 if the first member is less, 0 if they are identical, and
475 * > 0 if the second member is less (the first member is greater).
478 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
479 return(strcmp(m1->name, m2->name));
481 return(m1->type - m2->type);