]>
Commit | Line | Data |
---|---|---|
2d7360ca | 1 | /* $Header$ |
2 | * | |
3 | * Command line oriented SMS List tool. | |
4 | * | |
5 | * by Mark Rosenstein, September 1988. | |
6 | * | |
7 | * Copyright 1989 by the Massachusetts Institute of Technology. | |
8 | */ | |
9 | ||
10 | #include <mit-copyright.h> | |
11 | #include <stdio.h> | |
12 | #include <ctype.h> | |
13 | #include <sms.h> | |
14 | #include <sms_app.h> | |
15 | ||
16 | #ifndef LINT | |
17 | static char smslist_rcsid[] = "$Header$"; | |
18 | #endif | |
19 | ||
20 | ||
21 | struct member { | |
22 | int type; | |
23 | char *name; | |
24 | }; | |
25 | ||
26 | /* member types */ | |
27 | #define M_ANY 0 | |
28 | #define M_USER 1 | |
29 | #define M_LIST 2 | |
30 | #define M_STRING 3 | |
31 | ||
32 | /* flags from command line */ | |
33 | int infoflg, verbose, syncflg, memberflg, debugflg; | |
34 | ||
35 | /* various member lists */ | |
36 | struct save_queue *addlist, *dellist, *memberlist, *synclist; | |
37 | ||
38 | char *listname, *whoami; | |
39 | ||
40 | extern char *index(); | |
41 | extern int errno; | |
42 | ||
43 | int show_list_info(), show_list_count(), get_list_members(), scream(); | |
44 | struct member *parse_member(); | |
45 | ||
46 | ||
47 | ||
48 | main(argc, argv) | |
49 | int argc; | |
50 | char **argv; | |
51 | { | |
52 | int status; | |
53 | char **arg = argv; | |
54 | char *membervec[3]; | |
55 | struct member *memberstruct; | |
56 | ||
57 | /* clear all flags & lists */ | |
58 | infoflg = verbose = syncflg = memberflg = debugflg = 0; | |
59 | listname = NULL; | |
60 | addlist = sq_create(); | |
61 | dellist = sq_create(); | |
62 | memberlist = sq_create(); | |
63 | synclist = sq_create(); | |
64 | whoami = argv[0]; | |
65 | ||
66 | /* parse args, building addlist, dellist, & synclist */ | |
67 | while (++arg - argv < argc) { | |
68 | if (**arg == '-') | |
69 | switch((*arg)[1]) { | |
70 | case 'm': | |
71 | memberflg++; | |
72 | break; | |
73 | case 'D': | |
74 | debugflg++; | |
75 | break; | |
76 | case 'i': | |
77 | infoflg++; | |
78 | break; | |
79 | case 'v': | |
80 | verbose++; | |
81 | break; | |
82 | case 'a': | |
83 | if (arg - argv < argc - 1) { | |
84 | ++arg; | |
85 | if (memberstruct = parse_member(*arg)) | |
86 | sq_save_data(addlist, memberstruct); | |
87 | } else | |
88 | usage(argv); | |
89 | break; | |
90 | case 'd': | |
91 | if (arg - argv < argc - 1) { | |
92 | ++arg; | |
93 | if (memberstruct = parse_member(*arg)) | |
94 | sq_save_data(dellist, memberstruct); | |
95 | } else | |
96 | usage(argv); | |
97 | break; | |
98 | case 'f': | |
99 | if (arg - argv < argc - 1) { | |
100 | FILE *in; | |
101 | char buf[BUFSIZ]; | |
102 | ||
103 | syncflg++; | |
104 | ++arg; | |
105 | if (!strcmp(*arg, "-")) | |
106 | in = stdin; | |
107 | else { | |
108 | in = fopen(*arg, "r"); | |
109 | if (!in) { | |
110 | com_err(whoami, errno, " while opening %s for input", | |
111 | *arg); | |
112 | exit(2); | |
113 | } | |
114 | } | |
115 | while (fgets(buf, BUFSIZ, in)) | |
116 | if (memberstruct = parse_member(buf)) | |
117 | sq_save_data(synclist, memberstruct); | |
118 | if (!feof(in)) | |
119 | com_err(whoami, errno, " while reading from %s", *arg); | |
120 | } else | |
121 | usage(argv); | |
122 | break; | |
123 | default: | |
124 | usage(argv); | |
125 | } | |
126 | else if (listname == NULL) | |
127 | listname = *arg; | |
128 | else | |
129 | usage(argv); | |
130 | } | |
131 | if (listname == NULL) | |
132 | usage(argv); | |
133 | ||
134 | /* if no other options specified, turn on list members flag */ | |
135 | if (!(infoflg || syncflg || | |
136 | addlist->q_next != addlist || dellist->q_next != dellist)) | |
137 | memberflg++; | |
138 | ||
139 | /* fire up SMS */ | |
140 | if (status = sms_connect()) { | |
141 | com_err(whoami, status, " unable to connect to SMS"); | |
142 | exit(2); | |
143 | } | |
144 | if (status = sms_auth("blanche")) { | |
145 | com_err(whoami, status, " unable to authenticate to SMS"); | |
146 | exit(2); | |
147 | } | |
148 | ||
149 | /* display list info if requested to */ | |
150 | if (infoflg) { | |
151 | status = sms_query("get_list_info", 1, &listname, show_list_info,NULL); | |
152 | if (status) | |
153 | com_err(whoami, status, " while getting list information"); | |
154 | if (verbose && !memberflg) { | |
155 | status = sms_query("count_members_of_list", 1, &listname, | |
156 | show_list_count, NULL); | |
157 | if (status) | |
158 | com_err(whoami, status, " while getting list count"); | |
159 | } | |
160 | } | |
161 | ||
162 | /* if we're synchronizing to a file, we need to: | |
163 | * get the current members of the list | |
164 | * for each member of the sync file | |
165 | * if they are on the list, remove them from the in-memory copy | |
166 | * if they're not on the list, add them to add-list | |
167 | * if anyone is left on the in-memory copy, put them on the delete-list | |
168 | * lastly, reset memberlist so we can use it again later | |
169 | */ | |
170 | if (syncflg) { | |
171 | status = sms_query("get_members_of_list", 1, &listname, | |
172 | get_list_members, memberlist); | |
173 | if (status) | |
174 | com_err(whoami, status, " while getting members of list"); | |
175 | while (sq_get_data(synclist, &memberstruct)) { | |
176 | struct save_queue *q; | |
177 | int removed = 0; | |
178 | ||
179 | for (q = memberlist->q_next; q != memberlist; q = q->q_next) { | |
180 | if (membermatch(q->q_data, memberstruct)) { | |
181 | q->q_prev->q_next = q->q_next; | |
182 | q->q_next->q_prev = q->q_prev; | |
183 | removed++; | |
184 | break; | |
185 | } | |
186 | } | |
187 | if (!removed) | |
188 | sq_save_data(addlist, memberstruct); | |
189 | } | |
190 | while (sq_get_data(memberlist, &memberstruct)) | |
191 | sq_save_data(dellist, memberstruct); | |
192 | sq_destroy(memberlist); | |
193 | memberlist = sq_create(); | |
194 | } | |
195 | ||
196 | /* Process the add list */ | |
197 | while (sq_get_data(addlist, &memberstruct)) { | |
198 | membervec[0] = listname; | |
199 | membervec[2] = memberstruct->name; | |
200 | switch (memberstruct->type) { | |
201 | case M_ANY: | |
202 | case M_USER: | |
203 | membervec[1] = "USER"; | |
204 | status = sms_query("add_member_to_list", 3, membervec, scream, NULL); | |
205 | if (status == SMS_SUCCESS) | |
206 | break; | |
207 | else if (status != SMS_USER || memberstruct->type != M_ANY) { | |
208 | com_err(whoami, status, " while adding member %s to %s", | |
209 | memberstruct->name, listname); | |
210 | break; | |
211 | } | |
212 | case M_LIST: | |
213 | membervec[1] = "LIST"; | |
214 | status = sms_query("add_member_to_list", 3, membervec, | |
215 | scream, NULL); | |
216 | if (status == SMS_SUCCESS) | |
217 | break; | |
218 | else if (status != SMS_LIST || memberstruct->type != M_ANY) { | |
219 | com_err(whoami, status, " while adding member %s to %s", | |
220 | memberstruct->name, listname); | |
221 | break; | |
222 | } | |
223 | case M_STRING: | |
224 | membervec[1] = "STRING"; | |
225 | status = sms_query("add_member_to_list", 3, membervec, | |
226 | scream, NULL); | |
227 | if (status != SMS_SUCCESS) | |
228 | com_err(whoami, status, " while adding member %s to %s", | |
229 | memberstruct->name, listname); | |
230 | } | |
231 | } | |
232 | ||
233 | /* Process the delete list */ | |
234 | while (sq_get_data(dellist, &memberstruct)) { | |
235 | membervec[0] = listname; | |
236 | membervec[2] = memberstruct->name; | |
237 | switch (memberstruct->type) { | |
238 | case M_ANY: | |
239 | case M_USER: | |
240 | membervec[1] = "USER"; | |
241 | status = sms_query("delete_member_from_list", 3, membervec, | |
242 | scream, NULL); | |
243 | if (status == SMS_SUCCESS) | |
244 | break; | |
245 | else if ((status != SMS_USER && status != SMS_NO_MATCH) || | |
246 | memberstruct->type != M_ANY) { | |
247 | com_err(whoami, status, " while deleteing member %s from %s", | |
248 | memberstruct->name, listname); | |
249 | break; | |
250 | } | |
251 | case M_LIST: | |
252 | membervec[1] = "LIST"; | |
253 | status = sms_query("delete_member_from_list", 3, membervec, | |
254 | scream, NULL); | |
255 | if (status == SMS_SUCCESS) | |
256 | break; | |
257 | else if ((status != SMS_LIST && status != SMS_NO_MATCH) || | |
258 | memberstruct->type != M_ANY) { | |
259 | com_err(whoami, status, " while deleteing member %s from %s", | |
260 | memberstruct->name, listname); | |
261 | break; | |
262 | } | |
263 | case M_STRING: | |
264 | membervec[1] = "STRING"; | |
265 | status = sms_query("delete_member_from_list", 3, membervec, | |
266 | scream, NULL); | |
267 | if (status == SMS_STRING && memberstruct->type == M_ANY) | |
268 | com_err(whoami, 0, "Unable to find member %s to delete from %s", | |
269 | memberstruct->name, listname); | |
270 | else if (status != SMS_SUCCESS) | |
271 | com_err(whoami, status, " while deleteing member %s from %s", | |
272 | memberstruct->name, listname); | |
273 | } | |
274 | } | |
275 | ||
276 | /* Display the members of the list now, if requested */ | |
277 | if (memberflg) { | |
278 | status = sms_query("get_members_of_list", 1, &listname, | |
279 | get_list_members, memberlist); | |
280 | if (status) | |
281 | com_err(whoami, status, " while getting members of list"); | |
282 | while (sq_get_data(memberlist, &memberstruct)) { | |
283 | if (verbose) { | |
284 | char *s; | |
285 | switch (memberstruct->type) { | |
286 | case M_USER: | |
287 | s = "USER"; | |
288 | break; | |
289 | case M_LIST: | |
290 | s = "LIST"; | |
291 | break; | |
292 | case M_STRING: | |
293 | s = "STRING"; | |
294 | break; | |
295 | } | |
296 | printf("%s: %s\n", s, memberstruct->name); | |
297 | } else { | |
298 | if (memberstruct->type == M_LIST) | |
299 | printf("LIST:%s\n", memberstruct->name); | |
300 | else if (memberstruct->type == M_STRING && | |
301 | !index(memberstruct->name, '@')) | |
302 | printf("STRING:%s\n", memberstruct->name); | |
303 | else | |
304 | printf("%s\n", memberstruct->name); | |
305 | } | |
306 | } | |
307 | } | |
308 | ||
309 | /* We're done! */ | |
310 | sms_disconnect(); | |
311 | exit(0); | |
312 | } | |
313 | ||
314 | usage(argv) | |
315 | char **argv; | |
316 | { | |
317 | printf("Usage: %s [-i] [-v] [-m] listname [-a member] [-d member] [-f file]\n", | |
318 | argv[0]); | |
319 | exit(1); | |
320 | } | |
321 | ||
322 | ||
323 | show_list_info(argc, argv, hint) | |
324 | int argc; | |
325 | char **argv; | |
326 | int hint; | |
327 | { | |
328 | printf("List: %s\n", argv[0]); | |
329 | printf("Description: %s\n", argv[9]); | |
330 | printf("Flags: %s, %s, and %s\n", | |
331 | atoi(argv[1]) ? "active" : "inactive", | |
332 | atoi(argv[2]) ? "public" : "private", | |
333 | atoi(argv[3]) ? "hidden" : "visible"); | |
334 | printf("%s is %sa maillist, and is %sa group", argv[0], | |
335 | atoi(argv[4]) ? "" : "not ", | |
336 | atoi(argv[5]) ? "" : "not "); | |
337 | if (atoi(argv[5])) | |
338 | printf(" with GID %d\n", atoi(argv[6])); | |
339 | else | |
340 | printf("\n"); | |
341 | printf("Owner: %s %s\n", argv[7], argv[8]); | |
342 | printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]); | |
343 | return(SMS_CONT); | |
344 | } | |
345 | ||
346 | ||
347 | show_list_count(argc, argv, hint) | |
348 | int argc; | |
349 | char **argv; | |
350 | int hint; | |
351 | { | |
352 | printf("Members: %s\n", argv[0]); | |
353 | } | |
354 | ||
355 | ||
356 | get_list_members(argc, argv, q) | |
357 | int argc; | |
358 | char **argv; | |
359 | struct save_queue *q; | |
360 | { | |
361 | struct member *m; | |
362 | ||
363 | m = (struct member *) malloc(sizeof(struct member)); | |
364 | switch (argv[0][0]) { | |
365 | case 'U': | |
366 | m->type = M_USER; | |
367 | break; | |
368 | case 'L': | |
369 | m->type = M_LIST; | |
370 | break; | |
371 | case 'S': | |
372 | m->type = M_STRING; | |
373 | break; | |
374 | } | |
375 | m->name = strsave(argv[1]); | |
376 | sq_save_data(q, m); | |
377 | return(SMS_CONT); | |
378 | } | |
379 | ||
380 | ||
381 | scream() | |
382 | { | |
383 | fprintf(stderr, "Programmer botch\n"); | |
384 | exit(3); | |
385 | } | |
386 | ||
387 | ||
388 | struct member *parse_member(s) | |
389 | register char *s; | |
390 | { | |
391 | register struct member *m; | |
392 | char *p; | |
393 | ||
394 | while (*s && isspace(*s)) | |
395 | s++; | |
396 | p = s; | |
397 | while (*p && isprint(*p) && !isspace(*p) && *p != ';') | |
398 | p++; | |
399 | *p = 0; | |
400 | if (p == s || strlen(s) == 0) | |
401 | return(NULL); | |
402 | ||
403 | if ((m = (struct member *) malloc(sizeof(struct member))) == NULL) | |
404 | return(NULL); | |
405 | ||
406 | if (p = index(s, ':')) { | |
407 | *p = 0; | |
408 | m->name = ++p; | |
409 | if (!strcasecmp("user", s)) | |
410 | m->type = M_USER; | |
411 | else if (!strcasecmp("list", s)) | |
412 | m->type = M_LIST; | |
413 | else if (!strcasecmp("string", s)) | |
414 | m->type = M_STRING; | |
415 | else { | |
416 | m->type = M_STRING; | |
417 | *(--p) = ':'; | |
418 | m->name = s; | |
419 | } | |
420 | m->name = strsave(m->name); | |
421 | return(m); | |
422 | } | |
423 | m->name = strsave(s); | |
424 | if (index(s, '@') || index(s, '!') || index(s, '%')) | |
425 | m->type = M_STRING; | |
426 | else | |
427 | m->type = M_ANY; | |
428 | return(m); | |
429 | } | |
430 | ||
431 | ||
432 | int membermatch(m1, m2) | |
433 | struct member *m1, *m2; | |
434 | { | |
435 | if (strcmp(m1->name, m2->name)) | |
436 | return(0); | |
437 | if (m1->type == M_ANY || m2->type == M_ANY) | |
438 | return(1); | |
439 | if (m1->type == m2->type) | |
440 | return(1); | |
441 | else | |
442 | return(0); | |
443 | } |