/* $Header$ * * This generates the /usr/lib/aliases mail aliases file for the mailhub. * The aliases file will contain: * user pobox entries * maillist expansions * sublists of maillists * * (c) Copyright 1988, 1990 by the Massachusetts Institute of Technology. * For copying and distribution information, please see the file * . */ #include #include #include #include #include #include #include #include EXEC SQL INCLUDE sqlca; #define ML_WID 72 #define AL_MAX_WID 896 char *divide = "########################################################################"; extern int errno; char *whoami = "aliases.gen"; FILE *out; main(argc, argv) int argc; char **argv; { long tm = time(NULL); char filename[64], *targetfile; struct stat sb; int flag1, flag2, flag3; out = stdout; initialize_sms_error_table(); #ifsql INGRES EXEC SQL CONNECT sms; #endsql #ifsql INFORMIX EXEC SQL DATABASE sms; #endsql if (argc == 2) { if (stat(argv[1], &sb) == 0) { if (ModDiff (&flag1, "list", sb.st_mtime) || ModDiff (&flag2, "imembers", sb.st_mtime) || ModDiff (&flag3, "users", sb.st_mtime)) exit (MR_DATE); if (flag1 < 0 && flag2 < 0 && flag3 < 0) { fprintf(stderr, "File %s does not need to be rebuilt.\n", argv[1]); exit(MR_NO_CHANGE); } } targetfile = argv[1]; sprintf(filename, "%s~", targetfile); if ((out = fopen(filename, "w")) == NULL) { fprintf(stderr, "unable to open %s for output\n", filename); exit(MR_OCONFIG); } } else if (argc != 1) { fprintf(stderr, "usage: %s [outfile]\n", argv[0]); exit(MR_ARGS); } fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm)); fprintf(out, "# This file is automatically generated, do not edit it directly.\n%s\n\n", divide); get_info(); #ifsql INFORMIX EXEC SQL COMMIT WORK; #endif #ifsql INGRES EXEC SQL DISCONNECT; #endsql fprintf(stderr, "Dumping information\n"); do_mlists(out); do_poboxes(out); fprintf(out, "\n%s\n# End of aliases file\n%s\n", divide, divide); if (fclose(out)) { perror("close failed"); exit(MR_CCONFIG); } if (argc == 2) fix_file(targetfile); exit(MR_SUCCESS); } struct hash *users, *machines, *strings, *lists; struct user { char login[9]; char *pobox; }; struct member { struct member *next; char *name; int list_id; }; struct list { char *name; char maillist; char acl_t; char *description; int acl_id; struct member *m; }; get_info() { EXEC SQL BEGIN DECLARE SECTION; int id, maillistp, acl, pid, bid, mid; char name[129], type[9], buf[257]; EXEC SQL END DECLARE SECTION; char *s; register struct user *u; register struct list *l; register struct member *m; register struct list *memberlist; EXEC SQL WHENEVER SQLERROR GOTO sqlerr; /* get locks */ EXEC SQL SELECT modtime INTO :buf FROM list WHERE LIST_ID = 0; EXEC SQL SELECT modtime INTO :buf FROM list WHERE USERS_ID = 0; fprintf(stderr, "Loading machines\n"); machines = create_hash(1000); EXEC SQL DECLARE m_cursor CURSOR FOR SELECT mach_id, name FROM machine; EXEC SQL OPEN m_cursor; while (1) { EXEC SQL FETCH m_cursor INTO :id, :name; if (sqlca.sqlcode != 0) break; if (s = index(name, '.')) *s = 0; #ifdef ATHENA strcat(name, ".LOCAL"); #endif hash_store(machines, id, strsave(name)); } EXEC SQL CLOSE m_cursor; fprintf(stderr, "Loading strings\n"); strings = create_hash(2000); EXEC SQL DECLARE s_cursor CURSOR FOR SELECT string_id, string FROM strings; EXEC SQL OPEN s_cursor; while (1) { EXEC SQL FETCH s_cursor INTO :id, :name; if (sqlca.sqlcode != 0) break; hash_store(strings, id, strsave(strtrim(name))); } EXEC SQL CLOSE s_cursor; fprintf(stderr, "Loading users\n"); users = create_hash(12001); EXEC SQL DECLARE u_cursor CURSOR FOR SELECT users_id, login, potype, pop_id, box_id FROM users WHERE status = 1 OR status = 5 OR status = 6; EXEC SQL OPEN u_cursor; while (1) { EXEC SQL FETCH u_cursor INTO :id, :name, :type, :pid, :bid; if (sqlca.sqlcode != 0) break; u = (struct user *) malloc(sizeof(struct user)); strcpy(u->login, strtrim(name)); if (type[0] == 'P') { if (s = hash_lookup(machines, pid)) { sprintf(buf, "%s@%s", name, s); u->pobox = strsave(buf); } else { u->pobox = (char *) NULL; fprintf(stderr, "User %s's pobox is on a missing machine!\n", u->login); } } else if (type[0] == 'S') { if ((u->pobox = hash_lookup(strings, bid)) == NULL) { u->pobox = (char *) NULL; fprintf(stderr, "User %s's pobox string is missing!\n", u->login); } } else u->pobox = (char *) NULL; hash_store(users, id, u); } EXEC SQL CLOSE u_cursor; fprintf(stderr, "Loading lists\n"); lists = create_hash(15001); EXEC SQL DECLARE l_cursor CURSOR FOR SELECT list_id, name, maillist, desc, acl_type, acl_id FROM list WHERE active != 0; EXEC SQL OPEN l_cursor; while (1) { EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :buf, :type, :acl; if (sqlca.sqlcode != 0) break; l = (struct list *) malloc(sizeof(struct list)); l->name = strsave(strtrim(name)); l->maillist = maillistp; l->description = strsave(strtrim(buf)); l->acl_t = type[0]; l->acl_id = acl; l->m = (struct member *) NULL; hash_store(lists, id, l); } EXEC SQL CLOSE l_cursor; fprintf(stderr, "Loading members\n"); EXEC SQL DECLARE mem_cursor CURSOR FOR SELECT list_id, member_type, member_id FROM imembers WHERE direct = 1; EXEC SQL OPEN mem_cursor; while (1) { EXEC SQL FETCH mem_cursor INTO :id, :type, :mid; if (sqlca.sqlcode != 0) break; if (l = (struct list *) hash_lookup(lists, id)) { m = (struct member *) malloc(sizeof(struct member)); if (type[0] == 'U' && (u = (struct user *) hash_lookup(users, mid))) { m->list_id = 0; m->name = u->login; m->next = l->m; l->m = m; } else if (type[0] == 'L' && (memberlist = (struct list *) hash_lookup(lists, mid))) { m->list_id = mid; m->name = memberlist->name; m->next = l->m; l->m = m; } else if (type[0] == 'S' && (s = hash_lookup(strings, mid))) { m->list_id = 0; m->name = s; m->next = l->m; l->m = m; } } } EXEC SQL CLOSE mem_cursor; return; sqlerr: com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode); critical_alert("DCM", "Alias build encountered INGRES ERROR %d", sqlca.sqlcode); exit(MR_INGRES_ERR); } save_mlist(id, l, force) int id; register struct list *l; int force; { register struct member *m; struct list *l1; if (l->maillist == 2 || (l->maillist == 0 && !force)) return; if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name)) { l->maillist = 0; return; } l->maillist = 2; output_mlist(id, l); if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id))) save_mlist(0, l1, 1); for (m = l->m; m; m = m->next) { if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id))) save_mlist(0, l1, 1); } } int lwid, bol, awid; output_mlist(id, l) int id; register struct list *l; { struct list *l1; register struct member *m; struct user *u; put_fill(out, l->description); if (l->acl_t == 'L') { if (l1 = (struct list *) hash_lookup(lists, l->acl_id)) fprintf(out, "owner-%s: %s\n", l->name, l1->name); } else if (l->acl_t == 'U') { if (u = (struct user *) hash_lookup(users, l->acl_id)) fprintf(out, "owner-%s: %s\n", l->name, u->login); } fprintf(out, "%s: ", l->name); lwid = strlen(l->name) + 2; bol = 1; for (m = l->m; m; m = m->next) do_member(out, m->name); if (l->m == (struct member *)NULL) fprintf(out, "/dev/null"); fprintf(out, "\n\n"); } /* Extract mailing lists. Make a list of all mailinglists, then * process them, adding any sub-lists or acl lists to the list of lists * to be processed. If further sublists are encountered, repeat... */ do_mlists(out) FILE *out; { fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide); hash_step(lists, save_mlist, 0); } /* print out strings separated by commas, doing line breaks as appropriate */ do_member(out, s) FILE *out; register char *s; { register wwid; static int cont = 1; wwid = strlen(s); if (!bol && awid + wwid + 2 > AL_MAX_WID) { fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont); cont++; awid = lwid = 17 + wwid; fputs(s, out); return; } if (bol) { lwid += wwid; awid = lwid; fputs(s, out); bol = 0; return; } if (lwid + wwid + 2 > ML_WID) { fprintf(out, ",\n\t%s", s); awid += lwid + wwid + 2; lwid = wwid + 8; return; } lwid += wwid + 2; fprintf(out, ", %s", s); } do_pobox(id, u, out) int id; register struct user *u; FILE *out; { if (u->pobox) fprintf(out, "%s: %s\n", u->login, u->pobox); } /* Do user poboxes. Just step through the users table, and print any * we extracted earlier. */ do_poboxes(out) FILE *out; { fprintf(out, "\n%s\n# User Poboxes\n%s\n", divide, divide); hash_step(users, do_pobox, out); } put_fill(aliases, string) FILE *aliases; register char *string; { register char *c; register int lwid; register int wwid; if (*string == 0) return; fputs("# ", aliases); lwid = 3; while (1) { while (*string && *string == ' ') string++; c = (char *)index(string, ' '); if (c == 0) { wwid = strlen(string); } else { wwid = c - string; *c = 0; } if ((lwid + wwid) > ML_WID) { fputs("\n# ", aliases); lwid = 3; fputs(string, aliases); } else { fputs(string, aliases); } if (c == (char *)0) break; /* add a space after the word */ (void) fputc(' ', aliases); wwid++; lwid += wwid; string += wwid; /* add another if after a period */ if (*--c == '.') { (void) fputc(' ', aliases); lwid++; } } (void) fputc('\n', aliases); }