]>
Commit | Line | Data |
---|---|---|
7ac48069 | 1 | /* $Id$ |
bac4ceaa | 2 | * |
3 | * This generates the /usr/lib/aliases file for the mailhub. | |
4 | * | |
7ac48069 | 5 | * (c) Copyright 1988-1998 by the Massachusetts Institute of Technology. |
6 | * For copying and distribution information, please see the file | |
7 | * <mit-copyright.h>. | |
bac4ceaa | 8 | */ |
9 | ||
10 | #include <mit-copyright.h> | |
bac4ceaa | 11 | #include <moira.h> |
12 | #include <moira_site.h> | |
7ac48069 | 13 | |
bac4ceaa | 14 | #include <sys/stat.h> |
7ac48069 | 15 | |
16 | #include <ctype.h> | |
17 | #include <stdio.h> | |
18 | #include <stdlib.h> | |
19 | #include <string.h> | |
20 | ||
21 | #include "util.h" | |
22 | ||
bac4ceaa | 23 | EXEC SQL INCLUDE sqlca; |
24 | ||
7ac48069 | 25 | RCSID("$Header$"); |
26 | ||
bac4ceaa | 27 | char *whoami = "mailhub.gen"; |
9c04b191 | 28 | char *db = "moira/moira"; |
bac4ceaa | 29 | char *divide = "##############################################################"; |
30 | ||
b033c6ed | 31 | #define MAX_LINE_WIDTH 72 |
32 | #define MAX_ALIAS_WIDTH 592 | |
bac4ceaa | 33 | |
34 | #define FALSE 0 | |
35 | #define TRUE (!FALSE) | |
36 | ||
5eaef520 | 37 | FILE *out = stdout; |
bac4ceaa | 38 | |
7ac48069 | 39 | struct hash *users, *machines, *strings, *lists, *names; |
40 | struct user { | |
41 | char *login; | |
7ac48069 | 42 | char *pobox; |
43 | }; | |
44 | struct member { | |
45 | struct member *next; | |
46 | char *name; | |
47 | int list_id; | |
48 | }; | |
49 | struct list { | |
50 | char *name; | |
51 | char maillist; | |
52 | char *description; | |
53 | char acl_t; | |
54 | int acl_id; | |
55 | struct member *m; | |
56 | }; | |
57 | struct names { | |
58 | char *name; | |
59 | struct names *next; | |
60 | int keep; | |
61 | int id; | |
62 | }; | |
63 | ||
64 | void get_info(void); | |
65 | void save_mlist(int id, void *list, void *force); | |
66 | void insert_login(int id, void *user, void *hint); | |
7ac48069 | 67 | void insert_name(char *s, int id, int nodups, int copy); |
68 | int hashstr(char *s); | |
69 | void sort_info(void); | |
70 | void output_data(int dummy, void *names, void *out); | |
71 | void output_mlist(int id, struct list *l); | |
7ac48069 | 72 | void put_fill(FILE *aliases, char *string); |
73 | void do_people(void); | |
74 | ||
b033c6ed | 75 | int incount = 0; |
76 | ||
5eaef520 | 77 | int main(int argc, char **argv) |
bac4ceaa | 78 | { |
b033c6ed | 79 | time_t tm = time(NULL); |
dfaf9b68 | 80 | char filename[MAXPATHLEN], *targetfile; |
5eaef520 | 81 | struct stat sb; |
b033c6ed | 82 | int flag1, flag2; |
5eaef520 | 83 | |
84 | EXEC SQL CONNECT :db; | |
85 | ||
86 | if (argc == 2) | |
87 | { | |
88 | if (stat(argv[1], &sb) == 0) | |
89 | { | |
b033c6ed | 90 | if (ModDiff(&flag1, "users", sb.st_mtime) || |
91 | ModDiff(&flag2, "list", sb.st_mtime)) | |
5eaef520 | 92 | exit(MR_DATE); |
b033c6ed | 93 | if (flag1 < 0 && flag2 < 0) |
5eaef520 | 94 | { |
95 | fprintf(stderr, "File %s does not need to be rebuilt.\n", | |
96 | argv[1]); | |
97 | exit(MR_NO_CHANGE); | |
bac4ceaa | 98 | } |
99 | } | |
5eaef520 | 100 | targetfile = argv[1]; |
101 | sprintf(filename, "%s~", targetfile); | |
102 | if (!(out = fopen(filename, "w"))) | |
103 | { | |
104 | fprintf(stderr, "unable to open %s for output\n", filename); | |
105 | exit(MR_OCONFIG); | |
bac4ceaa | 106 | } |
5eaef520 | 107 | } |
108 | else if (argc != 1) | |
109 | { | |
110 | fprintf(stderr, "usage: %s [outfile]\n", argv[0]); | |
111 | exit(MR_ARGS); | |
bac4ceaa | 112 | } |
113 | ||
5eaef520 | 114 | fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm)); |
115 | fprintf(out, "# This file is automatically generated, " | |
116 | "do not edit it directly.\n%s\n\n", divide); | |
bac4ceaa | 117 | |
5eaef520 | 118 | get_info(); |
bac4ceaa | 119 | |
5eaef520 | 120 | EXEC SQL COMMIT; |
bac4ceaa | 121 | |
5eaef520 | 122 | fprintf(stderr, "Sorting Info\n"); |
123 | sort_info(); | |
bac4ceaa | 124 | |
5eaef520 | 125 | fprintf(stderr, "Dumping information\n"); |
126 | do_people(); | |
bac4ceaa | 127 | |
5eaef520 | 128 | fprintf(out, "\n%s\n# End of aliases file\n", divide); |
bac4ceaa | 129 | |
5eaef520 | 130 | if (fclose(out)) |
131 | { | |
132 | perror("close failed"); | |
133 | exit(MR_CCONFIG); | |
bac4ceaa | 134 | } |
135 | ||
5eaef520 | 136 | if (argc == 2) |
137 | fix_file(targetfile); | |
138 | exit(MR_SUCCESS); | |
bac4ceaa | 139 | } |
140 | ||
7ac48069 | 141 | void get_info(void) |
bac4ceaa | 142 | { |
5eaef520 | 143 | EXEC SQL BEGIN DECLARE SECTION; |
144 | int id, pid, bid, cnt, maillistp, acl, mid; | |
dfaf9b68 | 145 | char mname[MACHINE_NAME_SIZE], str[STRINGS_STRING_SIZE]; |
146 | char login[USERS_LOGIN_SIZE], potype[USERS_POTYPE_SIZE]; | |
147 | char lname[LIST_NAME_SIZE], desc[LIST_DESCRIPTION_SIZE]; | |
148 | char type[LIST_ACL_TYPE_SIZE]; | |
5eaef520 | 149 | EXEC SQL END DECLARE SECTION; |
150 | char *s; | |
44d12d58 | 151 | struct user *u; |
5eaef520 | 152 | struct list *l, *memberlist; |
44d12d58 | 153 | struct member *m; |
5eaef520 | 154 | |
155 | /* The following is declarative, not executed, | |
156 | * and so is dependent on where it is in the file, | |
157 | * not in the order of execution of statements. | |
158 | */ | |
159 | EXEC SQL WHENEVER SQLERROR GOTO sqlerr; | |
160 | ||
161 | cnt = 0; | |
b033c6ed | 162 | machines = create_hash(100); |
5eaef520 | 163 | |
164 | EXEC SQL DECLARE m_cursor CURSOR FOR | |
165 | SELECT mach_id, name | |
166 | FROM machine | |
167 | WHERE status = 1 | |
b033c6ed | 168 | AND mach_id IN ( SELECT UNIQUE pop_id FROM users ) |
5eaef520 | 169 | ORDER BY mach_id; |
170 | EXEC SQL OPEN m_cursor; | |
171 | while (1) | |
172 | { | |
dfaf9b68 | 173 | EXEC SQL FETCH m_cursor INTO :id, :mname; |
5eaef520 | 174 | if (sqlca.sqlcode) |
175 | break; | |
dfaf9b68 | 176 | if ((s = strchr(mname, '.'))) |
5eaef520 | 177 | *s = '\0'; |
178 | else | |
dfaf9b68 | 179 | strtrim(mname); |
bac4ceaa | 180 | #ifdef ATHENA |
dfaf9b68 | 181 | strcat(mname, ".LOCAL"); |
bac4ceaa | 182 | #endif |
dfaf9b68 | 183 | if (hash_store(machines, id, strdup(mname)) < 0) |
5eaef520 | 184 | { |
185 | fprintf(stderr, "Out of memory!\n"); | |
186 | exit(MR_NO_MEM); | |
bac4ceaa | 187 | } |
5eaef520 | 188 | cnt++; |
bac4ceaa | 189 | } |
5eaef520 | 190 | EXEC SQL CLOSE m_cursor; |
191 | ||
192 | fprintf(stderr, "Loaded %d machines\n", cnt); | |
193 | ||
194 | cnt = 0; | |
195 | strings = create_hash(11001); | |
196 | ||
197 | EXEC SQL DECLARE s_cursor CURSOR FOR | |
198 | SELECT string_id, string | |
199 | FROM strings | |
200 | ORDER BY string_id; | |
201 | EXEC SQL OPEN s_cursor; | |
202 | while (1) | |
203 | { | |
dfaf9b68 | 204 | EXEC SQL FETCH s_cursor INTO :id, :str; |
5eaef520 | 205 | if (sqlca.sqlcode) |
206 | break; | |
dfaf9b68 | 207 | if (hash_store(strings, id, strdup(strtrim(str))) < 0) |
5eaef520 | 208 | { |
209 | fprintf(stderr, "Out of memory!\n"); | |
210 | exit(MR_NO_MEM); | |
bac4ceaa | 211 | } |
5eaef520 | 212 | cnt++; |
bac4ceaa | 213 | } |
5eaef520 | 214 | EXEC SQL CLOSE s_cursor; |
215 | ||
216 | fprintf(stderr, "Loaded %d strings\n", cnt); | |
217 | ||
218 | cnt = 0; | |
219 | users = create_hash(13001); | |
220 | ||
221 | EXEC SQL DECLARE u_cursor CURSOR FOR | |
dfaf9b68 | 222 | SELECT users_id, login, potype, pop_id, box_id |
5eaef520 | 223 | FROM users |
224 | WHERE status != 3 | |
225 | ORDER BY users_id; | |
226 | EXEC SQL OPEN u_cursor; | |
227 | while (1) | |
228 | { | |
dfaf9b68 | 229 | EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :bid; |
5eaef520 | 230 | if (sqlca.sqlcode) |
231 | break; | |
7ac48069 | 232 | u = malloc(sizeof(struct user)); |
dfaf9b68 | 233 | u->login = strdup(strtrim(login)); |
5eaef520 | 234 | |
dfaf9b68 | 235 | if (potype[0] == 'P' && (s = hash_lookup(machines, pid))) |
5eaef520 | 236 | { |
dfaf9b68 | 237 | char *buf = malloc(strlen(u->login) + strlen(s) + 2); |
5eaef520 | 238 | sprintf(buf, "%s@%s", u->login, s); |
dfaf9b68 | 239 | u->pobox = buf; |
5eaef520 | 240 | } |
dfaf9b68 | 241 | else if (potype[0] == 'S') |
5eaef520 | 242 | u->pobox = hash_lookup(strings, bid); |
243 | else | |
244 | u->pobox = NULL; | |
245 | if (hash_store(users, id, u) < 0) | |
246 | { | |
247 | fprintf(stderr, "Out of memory!\n"); | |
248 | exit(MR_NO_MEM); | |
bac4ceaa | 249 | } |
5eaef520 | 250 | cnt++; |
bac4ceaa | 251 | } |
5eaef520 | 252 | EXEC SQL CLOSE u_cursor; |
253 | fprintf(stderr, "Loaded %d users\n", cnt); | |
254 | ||
255 | cnt = 0; | |
256 | lists = create_hash(15000); | |
257 | ||
258 | EXEC SQL DECLARE l_cursor CURSOR FOR | |
259 | SELECT list_id, name, maillist, description, acl_type, acl_id | |
260 | FROM list | |
261 | WHERE active != 0 | |
262 | ORDER BY list_id; | |
263 | EXEC SQL OPEN l_cursor; | |
264 | while (1) | |
265 | { | |
dfaf9b68 | 266 | EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl; |
5eaef520 | 267 | if (sqlca.sqlcode) |
268 | break; | |
7ac48069 | 269 | l = malloc(sizeof(struct list)); |
dfaf9b68 | 270 | l->name = strdup(strtrim(lname)); |
5eaef520 | 271 | l->maillist = maillistp; |
dfaf9b68 | 272 | l->description = strdup(strtrim(desc)); |
5eaef520 | 273 | l->acl_t = type[0]; |
274 | l->acl_id = acl; | |
275 | l->m = NULL; | |
276 | if (hash_store(lists, id, l) < 0) | |
277 | { | |
278 | fprintf(stderr, "Out of memory!\n"); | |
279 | exit(MR_NO_MEM); | |
bac4ceaa | 280 | } |
5eaef520 | 281 | cnt++; |
bac4ceaa | 282 | } |
5eaef520 | 283 | EXEC SQL CLOSE l_cursor; |
284 | fprintf(stderr, "Loaded %d lists\n", cnt); | |
285 | ||
286 | cnt = 0; | |
287 | ||
288 | EXEC SQL DECLARE m_cursor2 CURSOR FOR | |
289 | SELECT list_id, member_type, member_id | |
290 | FROM imembers | |
291 | WHERE direct = 1 | |
292 | ORDER BY list_id; | |
293 | EXEC SQL OPEN m_cursor2; | |
294 | while (1) | |
295 | { | |
296 | EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid; | |
297 | if (sqlca.sqlcode) | |
298 | break; | |
299 | cnt++; | |
7ac48069 | 300 | if ((l = hash_lookup(lists, id))) |
5eaef520 | 301 | { |
7ac48069 | 302 | m = malloc(sizeof(struct member)); |
303 | if (type[0] == 'U' && (u = hash_lookup(users, mid))) | |
5eaef520 | 304 | { |
305 | m->list_id = 0; | |
306 | m->name = u->login; | |
307 | m->next = l->m; | |
308 | l->m = m; | |
309 | } | |
7ac48069 | 310 | else if (type[0] == 'L' && (memberlist = hash_lookup(lists, mid))) |
5eaef520 | 311 | { |
312 | m->list_id = mid; | |
313 | m->name = memberlist->name; | |
314 | m->next = l->m; | |
315 | l->m = m; | |
316 | } | |
317 | else if (type[0] == 'S' && (s = hash_lookup(strings, mid))) | |
318 | { | |
319 | m->list_id = 0; | |
320 | m->next = l->m; | |
321 | l->m = m; | |
322 | m->name = s; | |
bac4ceaa | 323 | } |
324 | } | |
325 | } | |
5eaef520 | 326 | EXEC SQL CLOSE m_cursor2; |
327 | fprintf(stderr, "Loaded %d members\n", cnt); | |
328 | ||
329 | EXEC SQL COMMIT; | |
330 | return; | |
331 | sqlerr: | |
332 | db_error(sqlca.sqlcode); | |
333 | exit(MR_DBMS_ERR); | |
bac4ceaa | 334 | } |
335 | ||
336 | ||
7ac48069 | 337 | void save_mlist(int id, void *list, void *force) |
bac4ceaa | 338 | { |
44d12d58 | 339 | struct member *m; |
7ac48069 | 340 | struct list *l = list, *l1; |
bac4ceaa | 341 | |
5eaef520 | 342 | if (l->maillist > 1 || (l->maillist == 0 && !force)) |
343 | return; | |
bac4ceaa | 344 | |
5eaef520 | 345 | if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name)) |
346 | { | |
347 | l->maillist = 3; | |
348 | return; | |
bac4ceaa | 349 | } |
5eaef520 | 350 | l->maillist = 2; |
351 | insert_name(l->name, -1, TRUE, FALSE); | |
352 | output_mlist(id, l); | |
353 | ||
7ac48069 | 354 | if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id))) |
355 | save_mlist(0, l1, (void *)TRUE); | |
5eaef520 | 356 | |
357 | for (m = l->m; m; m = m->next) | |
358 | { | |
7ac48069 | 359 | if (m->list_id && (l1 = hash_lookup(lists, m->list_id))) |
360 | save_mlist(0, l1, (void *)TRUE); | |
bac4ceaa | 361 | } |
362 | } | |
363 | ||
364 | ||
7ac48069 | 365 | void insert_login(int id, void *user, void *hint) |
bac4ceaa | 366 | { |
7ac48069 | 367 | struct user *u = user; |
5eaef520 | 368 | if (u->pobox && u->login[0] != '#') |
369 | insert_name(u->login, id, TRUE, FALSE); | |
bac4ceaa | 370 | } |
371 | ||
7ac48069 | 372 | void insert_name(char *s, int id, int nodups, int copy) |
bac4ceaa | 373 | { |
5eaef520 | 374 | int code; |
44d12d58 | 375 | struct names *ns; |
5eaef520 | 376 | |
377 | incount++; | |
378 | code = hashstr(s); | |
7ac48069 | 379 | ns = hash_lookup(names, code); |
5eaef520 | 380 | if (!ns) |
381 | { | |
7ac48069 | 382 | if (!(ns = malloc(sizeof(struct names)))) |
5eaef520 | 383 | { |
384 | fprintf(stderr, "ran out of memory inserting name (sorting)\n"); | |
385 | exit(MR_NO_MEM); | |
bac4ceaa | 386 | } |
5eaef520 | 387 | if (copy) |
7ac48069 | 388 | ns->name = strdup(s); |
5eaef520 | 389 | else |
390 | ns->name = s; | |
391 | ns->keep = nodups; | |
392 | ns->id = id; | |
393 | ns->next = NULL; | |
394 | if (hash_store(names, code, ns) < 0) | |
395 | { | |
396 | fprintf(stderr, "Out of memory!\n"); | |
397 | exit(MR_NO_MEM); | |
bac4ceaa | 398 | } |
5eaef520 | 399 | return; |
bac4ceaa | 400 | } |
5eaef520 | 401 | if (strcasecmp(ns->name, s)) |
402 | { | |
403 | while (ns->next) | |
404 | { | |
405 | ns = ns->next; | |
406 | if (!strcasecmp(ns->name, s)) | |
407 | goto foundns; | |
bac4ceaa | 408 | } |
7ac48069 | 409 | if (!(ns->next = malloc(sizeof(struct names)))) |
5eaef520 | 410 | { |
411 | fprintf(stderr, "ran out of memory insterting name (sorting)\n"); | |
412 | exit(MR_NO_MEM); | |
bac4ceaa | 413 | } |
5eaef520 | 414 | ns = ns->next; |
415 | if (copy) | |
7ac48069 | 416 | ns->name = strdup(s); |
5eaef520 | 417 | else |
418 | ns->name = s; | |
419 | ns->keep = nodups; | |
420 | ns->id = id; | |
421 | ns->next = NULL; | |
422 | return; | |
bac4ceaa | 423 | } |
5eaef520 | 424 | foundns: |
425 | if (nodups || ns->keep) | |
426 | { | |
427 | if (nodups && ns->keep) | |
428 | fprintf(stderr, "duplicated name: %s\n", s); | |
429 | return; | |
bac4ceaa | 430 | } |
5eaef520 | 431 | ns->id = 0; |
bac4ceaa | 432 | } |
433 | ||
434 | ||
3ce369ab | 435 | /* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */ |
bac4ceaa | 436 | |
437 | static int illegalchars[] = { | |
5eaef520 | 438 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */ |
439 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */ | |
440 | 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */ | |
441 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */ | |
442 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */ | |
443 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */ | |
444 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */ | |
445 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */ | |
446 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
447 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
448 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
449 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
450 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
451 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
452 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
453 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
bac4ceaa | 454 | }; |
455 | ||
456 | ||
457 | /* While hashing the string, punt any illegal characters */ | |
458 | ||
44d12d58 | 459 | int hashstr(char *s) |
bac4ceaa | 460 | { |
44d12d58 | 461 | int result; |
462 | int c; | |
5eaef520 | 463 | |
7ac48069 | 464 | for (result = 0; (c = *s); s++) |
5eaef520 | 465 | { |
466 | if (illegalchars[c]) | |
467 | { | |
44d12d58 | 468 | char *p; |
5eaef520 | 469 | for (p = s; *p; p++) |
470 | *p = p[1]; | |
471 | continue; | |
bac4ceaa | 472 | } |
5eaef520 | 473 | if (isupper(c)) |
474 | c = *s = tolower(c); | |
475 | result = (result << 5) - result + c - '`'; | |
bac4ceaa | 476 | } |
5eaef520 | 477 | return result < 0 ? -result : result; |
bac4ceaa | 478 | } |
479 | ||
480 | ||
7ac48069 | 481 | void sort_info(void) |
bac4ceaa | 482 | { |
5eaef520 | 483 | names = create_hash(20001); |
484 | hash_step(users, insert_login, NULL); | |
485 | incount = 0; | |
486 | fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide); | |
487 | hash_step(lists, save_mlist, FALSE); | |
488 | fprintf(stderr, "Output %d lists\n", incount); | |
bac4ceaa | 489 | } |
490 | ||
491 | ||
7ac48069 | 492 | void output_data(int dummy, void *names, void *out) |
bac4ceaa | 493 | { |
7ac48069 | 494 | struct names *ns, *nms = names; |
44d12d58 | 495 | struct user *u; |
5eaef520 | 496 | |
497 | incount++; | |
498 | for (ns = nms; ns; ns = ns->next) | |
499 | { | |
500 | if (!ns->name[0] || !ns->name[1]) | |
501 | { | |
502 | fprintf(stderr, "punting %s due to short name\n", ns->name); | |
503 | continue; | |
bac4ceaa | 504 | } |
5eaef520 | 505 | if (ns->id > 0) |
506 | { | |
7ac48069 | 507 | u = hash_lookup(users, ns->id); |
5eaef520 | 508 | if (u->pobox) |
509 | fprintf(out, "%s: %s\n", ns->name, u->pobox); | |
bac4ceaa | 510 | } |
511 | } | |
512 | } | |
513 | ||
514 | ||
7ac48069 | 515 | void output_mlist(int id, struct list *l) |
bac4ceaa | 516 | { |
5eaef520 | 517 | struct list *l1; |
44d12d58 | 518 | struct member *m; |
519 | struct user *u; | |
b033c6ed | 520 | int line_width, alias_width, word_width, beginning; |
521 | static int cont = 1; | |
522 | char str[8]; | |
5eaef520 | 523 | |
524 | put_fill(out, l->description); | |
7ac48069 | 525 | if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id))) |
5eaef520 | 526 | fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name); |
7ac48069 | 527 | else if (l->acl_t == 'U' && (u = hash_lookup(users, l->acl_id))) |
5eaef520 | 528 | fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name); |
529 | else | |
530 | fprintf(out, "%s: ", l->name); | |
531 | ||
b033c6ed | 532 | alias_width = line_width = strlen(l->name) + 2; |
533 | beginning = 1; | |
5eaef520 | 534 | for (m = l->m; m; m = m->next) |
b033c6ed | 535 | { |
536 | word_width = strlen(m->name); | |
537 | ||
538 | if (!beginning && alias_width + word_width + 2 > MAX_ALIAS_WIDTH) | |
539 | { | |
540 | /* Make a continuation. */ | |
541 | sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97, | |
542 | rand() % 26 + 97, rand() % 26 + 97, | |
543 | rand() % 26 + 97, rand() % 26 + 97); | |
544 | fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str); | |
545 | cont++; | |
546 | alias_width = line_width = 17 + word_width; | |
547 | fputs(m->name, out); | |
548 | } | |
549 | else if (beginning) | |
550 | { | |
551 | /* Beginning of alias, so don't wrap. */ | |
552 | line_width += word_width; | |
553 | alias_width = line_width; | |
554 | fputs(m->name, out); | |
555 | beginning = 0; | |
556 | } | |
557 | else if (line_width + word_width + 2 > MAX_LINE_WIDTH) | |
558 | { | |
559 | /* Wrap. */ | |
560 | fprintf(out, ",\n\t%s", m->name); | |
561 | alias_width += line_width + word_width + 2; | |
562 | line_width = word_width + 8; | |
563 | } | |
564 | else | |
565 | { | |
566 | /* Continue line. */ | |
567 | line_width += word_width + 2; | |
568 | fprintf(out, ", %s", m->name); | |
569 | } | |
570 | } | |
5eaef520 | 571 | if (!l->m) |
572 | fprintf(out, "/dev/null"); | |
573 | fprintf(out, "\n\n"); | |
574 | incount++; | |
bac4ceaa | 575 | } |
576 | ||
b033c6ed | 577 | /* Write a word-wrapped list description to the aliases file as a |
578 | * comment. */ | |
7ac48069 | 579 | void put_fill(FILE *aliases, char *string) |
492f333e | 580 | { |
44d12d58 | 581 | char *c; |
b033c6ed | 582 | int line_width; |
583 | int word_width; | |
492f333e | 584 | |
5eaef520 | 585 | if (!string || !*string) |
586 | return; | |
587 | fputs("# ", aliases); | |
b033c6ed | 588 | line_width = 3; |
5eaef520 | 589 | |
590 | while (1) | |
591 | { | |
592 | while (*string == ' ') | |
593 | string++; | |
594 | c = strchr(string, ' '); | |
595 | if (!c) | |
b033c6ed | 596 | word_width = strlen(string); |
5eaef520 | 597 | else |
598 | { | |
b033c6ed | 599 | word_width = c - string; |
5eaef520 | 600 | *c = '\0'; |
492f333e | 601 | } |
602 | ||
b033c6ed | 603 | if (line_width + word_width > MAX_LINE_WIDTH) |
5eaef520 | 604 | { |
605 | fputs("\n# ", aliases); | |
b033c6ed | 606 | line_width = 3; |
5eaef520 | 607 | fputs(string, aliases); |
608 | } | |
609 | else | |
610 | fputs(string, aliases); | |
611 | ||
612 | if (!c) | |
613 | break; | |
614 | /* add a space after the word */ | |
615 | fputc(' ', aliases); | |
b033c6ed | 616 | word_width++; |
617 | line_width += word_width; | |
618 | string += word_width; | |
5eaef520 | 619 | /* add another if after a period */ |
620 | if (*--c == '.') | |
621 | { | |
622 | fputc(' ', aliases); | |
b033c6ed | 623 | line_width++; |
492f333e | 624 | } |
625 | } | |
626 | ||
5eaef520 | 627 | fputc('\n', aliases); |
492f333e | 628 | } |
629 | ||
630 | ||
7ac48069 | 631 | void do_people(void) |
bac4ceaa | 632 | { |
5eaef520 | 633 | incount = 0; |
634 | fprintf(out, "\n%s\n# People\n%s\n", divide, divide); | |
635 | hash_step(names, output_data, out); | |
636 | fprintf(stderr, "Output %d entries\n", incount); | |
bac4ceaa | 637 | } |