X-Git-Url: http://andersk.mit.edu/gitweb/moira.git/blobdiff_plain/c9f91d67279585ae3c7bd64b1c255287c1c463dd..41ecb0f6e2cc3e9b4d29aad9672b8b39c70c4b95:/gen/mailhub.pc diff --git a/gen/mailhub.pc b/gen/mailhub.pc index f12de554..6e531aa5 100644 --- a/gen/mailhub.pc +++ b/gen/mailhub.pc @@ -1,826 +1,559 @@ - -/* $Header$ +/* $Id$ * * This generates the /usr/lib/aliases file for the mailhub. * - * (c) Copyright 1988, 1990 by the Massachusetts Institute of Technology. - * For copying and distribution information, please see the file - * . + * (c) Copyright 1988-1998 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * . */ #include -#include -#include -#include #include #include -#include + #include -#include + +#include +#include +#include +#include + +#include "util.h" + EXEC SQL INCLUDE sqlca; +RCSID("$Header$"); -extern int errno; char *whoami = "mailhub.gen"; char *db = "moira/moira"; -char *perm_malloc(); -char *pstrsave(); char *divide = "##############################################################"; -#define ML_WID 72 -#define AL_MAX_WID 592 +#define MAX_LINE_WIDTH 72 +#define MAX_ALIAS_WIDTH 592 #define FALSE 0 #define TRUE (!FALSE) -FILE *out= stdout; +struct hash *users, *machines, *strings, *lists; +struct user { + char *login; + char *pobox; +}; +struct member { + struct member *next; + char *name; + int list_id; +}; +struct list { + char *name; + char maillist; + char *description; + char acl_t; + int acl_id; + char mailman; + char *mailman_server; + struct member *m; +}; +void get_info(void); +int check_string(char *s); +void output_login(int dummy, void *names, void *out); +void output_mlist(int id, void *list, void *out); +void output_membership(struct list *l, FILE *out); +void put_fill(FILE *aliases, char *string); +void do_people(void); + +int incount = 0; -main(argc, argv) -int argc; -char **argv; +int main(int argc, char **argv) { - long tm = time(NULL); - char filename[64], *targetfile; - struct stat sb; - EXEC SQL BEGIN DECLARE SECTION; - int flag; - EXEC SQL END DECLARE SECTION; - - EXEC SQL CONNECT :db; - - if (argc == 2) { - if (stat(argv[1], &sb) == 0) { - if (ModDiff (&flag, "users", sb.st_mtime)) - exit(MR_DATE); - if (flag < 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); + time_t tm = time(NULL); + char filename[MAXPATHLEN], *targetfile; + FILE *out = stdout; + + srand(tm); + EXEC SQL CONNECT :db; + + if (argc == 2) + { + targetfile = argv[1]; + sprintf(filename, "%s~", targetfile); + if (!(out = fopen(filename, "w"))) + { + 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); + } + 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); + 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(); + get_info(); - EXEC SQL COMMIT; + EXEC SQL COMMIT; - fprintf(stderr, "Sorting Info\n"); - sort_info(); + incount = 0; + fprintf(out, "\n%s\n# Mailing lists\n%s\n\n", divide, divide); + hash_step(lists, output_mlist, out); + fprintf(stderr, "Output %d lists\n", incount); - fprintf(stderr, "Dumping information\n"); - do_people(); + incount = 0; + fprintf(out, "\n%s\n# People\n%s\n\n", divide, divide); + hash_step(users, output_login, out); + fprintf(stderr, "Output %d users\n", incount); - fprintf(out, "\n%s\n# End of aliases file\n", divide); + fprintf(out, "\n%s\n# End of aliases file\n", divide); - if (fclose(out)) { - perror("close failed"); - exit(MR_CCONFIG); + if (fclose(out)) + { + perror("close failed"); + exit(MR_CCONFIG); } - if (argc == 2) - fix_file(targetfile); - exit(MR_SUCCESS); + if (argc == 2) + fix_file(targetfile); + exit(MR_SUCCESS); } - - -struct hash *users, *machines, *strings, *lists, *names; -struct user { - char *login; - char *first; - char *last; - char mi; - char *pobox; -}; -struct member { - struct member *next; - char *name; - int list_id; -}; -struct list { - char *name; - char maillist; - char *description; - char acl_t; - int acl_id; - struct member *m; -}; -struct names { - char *name; - struct names *next; - int keep; - int id; -}; - - -get_info() +void get_info(void) { - EXEC SQL BEGIN DECLARE SECTION; - int id, pid, bid, cnt, maillistp, acl, mid; - char name[129], type[9], fname[17], mname[17], lname[17], buf[257]; - EXEC SQL END DECLARE SECTION; - char *s; - register struct user *u; - struct list *l, *memberlist; - register struct member *m; - - /* The following is declarative, not executed, - * and so is dependent on where it is in the file, - * not in the order of execution of statements. - */ - EXEC SQL WHENEVER SQLERROR GOTO sqlerr; - - cnt = 0; - machines = create_hash(1000); - - EXEC SQL DECLARE m_cursor CURSOR FOR - SELECT mach_id, name - FROM machine - WHERE status=1 - ORDER BY mach_id; - EXEC SQL OPEN m_cursor; - while (1) { - EXEC SQL FETCH m_cursor INTO :id, :name; - if (sqlca.sqlcode != 0) break; - if (s = strchr(name, '.')) - *s = 0; - else - strtrim(name); + EXEC SQL BEGIN DECLARE SECTION; + int id, pid, iid, bid, cnt, maillistp, acl, mid, mailman; + char mname[MACHINE_NAME_SIZE], str[STRINGS_STRING_SIZE]; + char login[USERS_LOGIN_SIZE], potype[USERS_POTYPE_SIZE]; + char lname[LIST_NAME_SIZE], desc[LIST_DESCRIPTION_SIZE]; + char type[LIST_ACL_TYPE_SIZE], mailman_server[MACHINE_NAME_SIZE]; + EXEC SQL END DECLARE SECTION; + char *s; + struct user *u; + struct list *l, *memberlist; + struct member *m; + + /* The following is declarative, not executed, + * and so is dependent on where it is in the file, + * not in the order of execution of statements. + */ + EXEC SQL WHENEVER SQLERROR GOTO sqlerr; + + cnt = 0; + machines = create_hash(100); + + EXEC SQL DECLARE m_cursor CURSOR FOR + SELECT mach_id, name + FROM machine + WHERE status = 1 + AND ( mach_id IN ( SELECT UNIQUE pop_id FROM users ) OR + mach_id IN ( SELECT UNIQUE mach_id FROM filesys + WHERE type = 'IMAP' ) ) + ORDER BY mach_id; + EXEC SQL OPEN m_cursor; + while (1) + { + EXEC SQL FETCH m_cursor INTO :id, :mname; + if (sqlca.sqlcode) + break; + if ((s = strchr(mname, '.'))) + *s = '\0'; + else + strtrim(mname); #ifdef ATHENA - strcat(name, ".LOCAL"); + strcat(mname, ".LOCAL"); #endif - if (hash_store(machines, id, pstrsave(name)) < 0) { - fprintf(stderr, "Out of memory!\n"); - exit(MR_NO_MEM); - } - cnt++; - } - EXEC SQL CLOSE m_cursor; - - fprintf(stderr, "Loaded %d machines\n", cnt); - - cnt = 0; - strings = create_hash(11001); - - EXEC SQL DECLARE s_cursor CURSOR FOR - SELECT string_id, string - FROM strings - ORDER BY string_id; - EXEC SQL OPEN s_cursor; - while (1) { - EXEC SQL FETCH s_cursor INTO :id, :name; - if (sqlca.sqlcode != 0) break; - if (hash_store(strings, id, pstrsave(strtrim(name))) < 0) { - fprintf(stderr, "Out of memory!\n"); - exit(MR_NO_MEM); - } - cnt++; - } - EXEC SQL CLOSE s_cursor; - - fprintf(stderr, "Loaded %d strings\n", cnt); - - cnt = 0; - users = create_hash(13001); - - EXEC SQL DECLARE u_cursor CURSOR FOR - SELECT users_id, login, first, middle, last, potype, pop_id, box_id - FROM users - WHERE status != 3 - ORDER BY users_id; - EXEC SQL OPEN u_cursor; - while (1) { - EXEC SQL FETCH u_cursor INTO :id, :name, :fname, :mname, :lname, - :type, :pid, :bid; - if (sqlca.sqlcode != 0) break; - u = (struct user *) perm_malloc(sizeof(struct user)); - u->login = pstrsave(strtrim(name)); - u->first = pstrsave(strtrim(fname)); - u->last = pstrsave(strtrim(lname)); - if (mname[0] != ' ') - u->mi = mname[0]; - else - u->mi = 0; - - if (type[0] == 'P' && (s = hash_lookup(machines, pid))) { - sprintf(buf, "%s@%s", u->login, s); - u->pobox = pstrsave(buf); - } else if (type[0] == 'S') { - u->pobox = hash_lookup(strings, bid); - } else - u->pobox = (char *) NULL; - if (hash_store(users, id, u) < 0) { - fprintf(stderr, "Out of memory!\n"); - exit(MR_NO_MEM); + if (hash_store(machines, id, strdup(mname)) < 0) + { + fprintf(stderr, "Out of memory!\n"); + exit(MR_NO_MEM); } - cnt++; + cnt++; } - EXEC SQL CLOSE u_cursor; - fprintf(stderr, "Loaded %d users\n", cnt); - - cnt = 0; - lists = create_hash(15000); - - EXEC SQL DECLARE l_cursor CURSOR FOR - SELECT list_id, name, maillist, description, acl_type, acl_id - FROM list - WHERE active != 0 - ORDER BY list_id; - 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 *) perm_malloc(sizeof(struct list)); - l->name = pstrsave(strtrim(name)); - l->maillist = maillistp; - l->description = pstrsave(strtrim(buf)); - l->acl_t = type[0]; - l->acl_id = acl; - l->m = (struct member *) NULL; - if (hash_store(lists, id, l) < 0) { - fprintf(stderr, "Out of memory!\n"); - exit(MR_NO_MEM); + EXEC SQL CLOSE m_cursor; + + fprintf(stderr, "Loaded %d machines\n", cnt); + + cnt = 0; + strings = create_hash(11001); + + EXEC SQL DECLARE s_cursor CURSOR FOR + SELECT string_id, string + FROM strings + ORDER BY string_id; + EXEC SQL OPEN s_cursor; + while (1) + { + EXEC SQL FETCH s_cursor INTO :id, :str; + if (sqlca.sqlcode) + break; + if (hash_store(strings, id, strdup(strtrim(str))) < 0) + { + fprintf(stderr, "Out of memory!\n"); + exit(MR_NO_MEM); } - cnt++; + cnt++; } - EXEC SQL CLOSE l_cursor; - fprintf(stderr, "Loaded %d lists\n", cnt); - - cnt = 0; - - EXEC SQL DECLARE m_cursor2 CURSOR FOR - SELECT list_id, member_type, member_id - FROM imembers - WHERE direct = 1 - ORDER BY list_id; - EXEC SQL OPEN m_cursor2; - while (1) { - EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid; - if (sqlca.sqlcode != 0) break; - cnt++; - if (l = (struct list *) hash_lookup(lists, id)) { - m = (struct member *) perm_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->next = l->m; - l->m = m; - m->name = s; + EXEC SQL CLOSE s_cursor; + + fprintf(stderr, "Loaded %d strings\n", cnt); + + cnt = 0; + users = create_hash(13001); + + EXEC SQL DECLARE u_cursor CURSOR FOR + SELECT users_id, login, potype, pop_id, imap_id, box_id + FROM users + WHERE status != 3 + ORDER BY users_id; + EXEC SQL OPEN u_cursor; + while (1) + { + char *saddr = NULL, *paddr = NULL; + + EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :iid, :bid; + if (sqlca.sqlcode) + break; + u = malloc(sizeof(struct user)); + u->login = strdup(strtrim(login)); + + if (!strcmp(strtrim(potype), "NONE")) + u->pobox = NULL; + else + { + /* If SMTP or SPLIT, get SMTP address. */ + if (potype[0] == 'S') + { + saddr = hash_lookup(strings, bid); + + /* If SMTP, clear pid and iid. */ + if (potype[1] == 'M') + pid = iid = 0; } - } - } - EXEC SQL CLOSE m_cursor2; - fprintf(stderr, "Loaded %d members\n", cnt); - - EXEC SQL COMMIT; - return; - sqlerr: - db_error(sqlca.sqlcode); - exit(MR_DBMS_ERR); -} + /* If IMAP, or SPLIT with IMAP, set pid to mach_id. */ + if (potype[0] == 'I' || (potype[0] == 'S' && iid)) + { + EXEC SQL SELECT mach_id INTO :pid FROM filesys + WHERE filsys_id = :iid; + } -save_mlist(id, l, force) -int id; -struct list *l; -int force; -{ - register struct member *m; - register struct list *l1; - - if (l->maillist > 1 || - (l->maillist == 0 && !force)) - return; - - if (l->m && l->m->next == NULL && - !strcasecmp(l->name, l->m->name)) { - l->maillist = 3; - return; - } - l->maillist = 2; - insert_name(l->name, -1, TRUE, FALSE); - output_mlist(id, l); - - if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id))) - save_mlist(0, l1, TRUE); - - 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, TRUE); - } -} - - -insert_login(id, u, dummy) -int id; -struct user *u; -int dummy; -{ - if (u->pobox && u->login[0] != '#') - insert_name(u->login, id, TRUE, FALSE); -} - -void insert_names(id, u, dummy) -int id; -struct user *u; -int dummy; -{ - char buffer[256]; - - insert_name(u->last, id, FALSE, FALSE); - sprintf(buffer, "%s_%s", u->first, u->last); - insert_name(buffer, id, FALSE, TRUE); -/* sprintf(buffer, "%c_%s", u->first[0], u->last); - insert_name(buffer, id, FALSE, TRUE); */ - if (u->mi) { - sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last); - insert_name(buffer, id, FALSE, TRUE); - } -} - -int incount = 0; + if (pid && (s = hash_lookup(machines, pid))) + { + paddr = malloc(strlen(u->login) + strlen(s) + 2); + sprintf(paddr, "%s@%s", u->login, s); + } -insert_name(s, id, nodups, copy) -char *s; -int id; -int nodups; -int copy; -{ - int code; - register struct names *ns; - - incount++; - code = hashstr(s); - ns = (struct names *) hash_lookup(names, code); - if (ns == NULL) { - if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) { - fprintf(stderr, "ran out of memory inserting name (sorting)\n"); - exit(MR_NO_MEM); + if (paddr && saddr) + { + u->pobox = malloc(strlen(paddr) + strlen(saddr) + 3); + sprintf(u->pobox, "%s, %s", paddr, saddr); + free(paddr); + } + else if (paddr) + u->pobox = paddr; + else + u->pobox = saddr; } - if (copy) - ns->name = pstrsave(s); - else - ns->name = s; - ns->keep = nodups; - ns->id = id; - ns->next = NULL; - if (hash_store(names, code, ns) < 0) { - fprintf(stderr, "Out of memory!\n"); - exit(MR_NO_MEM); + + check_string(u->login); + if (hash_store(users, id, u) < 0) + { + fprintf(stderr, "Out of memory!\n"); + exit(MR_NO_MEM); } - return; + cnt++; } - if (strcasecmp(ns->name, s)) { - while (ns->next) { - ns = ns->next; - if (!strcasecmp(ns->name, s)) - goto foundns; + EXEC SQL CLOSE u_cursor; + fprintf(stderr, "Loaded %d users\n", cnt); + + cnt = 0; + lists = create_hash(15000); + + EXEC SQL DECLARE l_cursor CURSOR FOR + SELECT l.list_id, l.name, l.maillist, l.description, l.acl_type, l.acl_id, + l.mailman, m.name + FROM list l, machine m + WHERE active != 0 AND l.mailman_id = m.mach_id + ORDER BY list_id; + EXEC SQL OPEN l_cursor; + while (1) + { + EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl, + :mailman, :mailman_server; + if (sqlca.sqlcode) + break; + l = malloc(sizeof(struct list)); + l->name = strdup(strtrim(lname)); + l->maillist = maillistp; + l->description = strdup(strtrim(desc)); + l->acl_t = type[0]; + l->acl_id = acl; + l->mailman = mailman; + l->mailman_server = strdup(strtrim(mailman_server)); + l->m = NULL; + if (hash_store(lists, id, l) < 0) + { + fprintf(stderr, "Out of memory!\n"); + exit(MR_NO_MEM); } - if ((ns->next = (struct names *) perm_malloc(sizeof(struct names))) - == NULL) { - fprintf(stderr, "ran out of memory insterting name (sorting)\n"); - exit(MR_NO_MEM); - } - ns = ns->next; - if (copy) - ns->name = pstrsave(s); - else - ns->name = s; - ns->keep = nodups; - ns->id = id; - ns->next = NULL; - return; - } - foundns: - if (nodups || ns->keep) { - if (nodups && ns->keep) - fprintf(stderr, "duplicated name: %s\n", s); - return; + cnt++; } - ns->id = 0; -} - - -/* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */ - -static int illegalchars[] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */ - 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -}; - - -/* While hashing the string, punt any illegal characters */ - -int hashstr(s) -register char *s; -{ - register int result; - register int c; - - for (result = 0; c = *s; s++) { - if (illegalchars[c]) { - register char *p; - for (p = s; *p; p++) - *p = p[1]; - continue; + EXEC SQL CLOSE l_cursor; + fprintf(stderr, "Loaded %d lists\n", cnt); + + cnt = 0; + + EXEC SQL DECLARE m_cursor2 CURSOR FOR + SELECT list_id, member_type, member_id + FROM imembers + WHERE direct = 1 + ORDER BY list_id; + EXEC SQL OPEN m_cursor2; + while (1) + { + EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid; + if (sqlca.sqlcode) + break; + cnt++; + if ((l = hash_lookup(lists, id))) + { + m = malloc(sizeof(struct member)); + if (type[0] == 'U' && (u = 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 = 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->next = l->m; + l->m = m; + m->name = s; + } } - if (isupper(c)) - c = *s = tolower(c); -/* result = result * 31 + *s; */ - result = (result << 5) - result + c - '`'; } - return(result < 0 ? -result : result); + EXEC SQL CLOSE m_cursor2; + fprintf(stderr, "Loaded %d members\n", cnt); + + EXEC SQL COMMIT; + return; +sqlerr: + db_error(sqlca.sqlcode); + exit(MR_DBMS_ERR); } -sort_info() +void output_login(int dummy, void *user, void *out) { - names = create_hash(20001); - hash_step(users, insert_login, NULL); - incount = 0; - fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide); - hash_step(lists, save_mlist, FALSE); - fprintf(stderr, "Output %d lists\n", incount); - hash_step(users, insert_names, NULL); - fprintf(stderr, "Inserted %d names\n", incount); -} + struct user *u = user; - -output_data(dummy, nms, out) -int dummy; -struct names *nms; -FILE *out; -{ - register struct names *ns; - register struct user *u; - - incount++; - for (ns = nms; ns; ns = ns->next) { - if (ns->name[0] == 0 || ns->name[1] == 0) { - fprintf(stderr, "punting %s due to short name\n", ns->name); - continue; - } - if (ns->id > 0) { - u = (struct user *) hash_lookup(users, ns->id); - if (u->pobox) { - fprintf(out, "%s: %s\n", ns->name, u->pobox); - } else { - fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name); - } - } else if (ns->id == 0) { - fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name); - } - } + incount++; + if (u->pobox && check_string(u->login) && u->login[0] != '#') + fprintf(out, "%s: %s\n", u->login, u->pobox); } +int line_width, alias_width; +static const char *mailman_suffixes[] = { "-admin", "-owner", "-request", + "-bounces", "-confirm", "-join", + "-leave", "-subscribe", + "-unsubscribe", NULL }; -int lwid, bol, awid; - -output_mlist(id, l) -int id; -register struct list *l; +void output_mlist(int id, void *list, void *out) { - struct list *l1; - register struct member *m; - register struct user *u; - - put_fill(out, l->description); - if (l->acl_t == 'L' && - (l1 = (struct list *) hash_lookup(lists, l->acl_id))) - fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name); - else if (l->acl_t == 'U' && - (u = (struct user *) hash_lookup(users, l->acl_id))) - fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name); - else - 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"); - incount++; -} + struct list *l = list, *l1; + struct user *u; + int len = strlen(l->name), i; + if (!l->maillist || !check_string(l->name)) + return; -/* print out strings separated by commas, doing line breaks as appropriate */ + /* If standard user group appears on a list, substitute in the user. */ + if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name)) + return; -do_member(out, s) -FILE *out; -register char *s; -{ - register wwid; - static int cont = 1; - char str[8]; - - wwid = strlen(s); - - if (!bol && awid + wwid + 2 > AL_MAX_WID) { - sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97, - rand() % 26 + 97, rand() % 26 + 97, - rand() % 26 + 97, rand() % 26 + 97); - str[6] = '\0'; - fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str); - cont++; - awid = lwid = 17 + wwid; - fputs(s, out); - return; - } + put_fill(out, l->description); - if (bol) { - lwid += wwid; - awid = lwid; - fputs(s, out); - bol = 0; - return; + if (l->mailman && strcmp(l->mailman_server, "[NONE]")) + { + for (i = 0; mailman_suffixes[i]; i++) + fprintf(out, "%s%s: %s%s@%s\n", l->name, mailman_suffixes[i], l->name, + mailman_suffixes[i], l->mailman_server); + fprintf(out, "owner-%s: %s-owner@%s\n", l->name, l->name, + l->mailman_server); } - if (lwid + wwid + 2 > ML_WID) { - fprintf(out, ",\n\t%s", s); - awid += lwid + wwid + 2; - lwid = wwid + 8; - return; + else if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id))) + { + fprintf(out, "owner-%s: ", l->name); + if ((l1->maillist) && (strcmp(l->name, l1->name))) + fprintf(out, "%s\n", l1->name); + else + { + alias_width = line_width = len + 8; + output_membership(l1, out); + fprintf(out, "\n"); + } } - lwid += wwid + 2; - fprintf(out, ", %s", s); + else if (l->acl_t == 'U' && (u = hash_lookup(users, l->acl_id))) + fprintf(out, "owner-%s: %s\n", l->name, u->login); + + fprintf(out, "%s: ", l->name); + alias_width = line_width = len + 2; + output_membership(l, out); + fprintf(out, "\n\n"); + incount++; } - -put_fill(aliases, string) -FILE *aliases; -register char *string; +void output_membership(struct list *l, FILE *out) { - register char *c; - register int lwid; - register int wwid; - - if (string == 0 || *string == 0) return; - fputs("# ", aliases); - lwid = 3; - - while (1) { - while (*string == ' ') string++; - c = (char *)strchr(string, ' '); - if (c == 0) { - wwid = strlen(string); - } else { - wwid = c - string; - *c = 0; + struct member *m; + struct list *l1; + int word_width, linestart = 1; + static int cont = 1; + char str[8]; + + for (m = l->m; m; m = m->next) + { + word_width = strlen(m->name); + + if (!linestart && alias_width + word_width + 2 > MAX_ALIAS_WIDTH) + { + /* Make a continuation. */ + sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97, + rand() % 26 + 97, rand() % 26 + 97, + rand() % 26 + 97, rand() % 26 + 97); + fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str); + cont++; + alias_width = line_width = 17 + word_width; } - - if ((lwid + wwid) > ML_WID) { - fputs("\n# ", aliases); - lwid = 3; - fputs(string, aliases); - } else { - fputs(string, aliases); + else if (linestart) + { + /* First word on line, so we can't wrap. */ + line_width += word_width; + alias_width = line_width; + linestart = 0; } - - 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++; + else if (line_width + word_width + 2 > MAX_LINE_WIDTH) + { + /* Wrap. */ + fputs(",\n\t", out); + alias_width += line_width + word_width + 2; + line_width = word_width + 8; + } + else + { + /* Continue line. */ + line_width += word_width + 2; + fputs(", ", out); } - } - - (void) fputc('\n', aliases); -} - - -do_people() -{ - incount = 0; - fprintf(out, "\n%s\n# People\n%s\n", divide, divide); - hash_step(names, output_data, out); - fprintf(stderr, "Output %d entries\n", incount); -} - - -#define chunk_size 102400 - -char *perm_malloc(size) -unsigned size; -{ - static char *pool = NULL; - static unsigned pool_size = 0; - register char *ret; - - if (size > pool_size) { - pool = (char *) malloc(chunk_size); - pool_size = chunk_size; - } - ret = pool; - pool += size; - pool = (char *)(((unsigned) (pool + 3)) & ~3); - pool_size -= (pool - ret); - return(ret); -} - -/* - * Make a (permenant) copy of a string. - */ -char * -pstrsave(s) - char *s; -{ - register int len; - register char *p; - /* Kludge for sloppy string semantics */ - if (!s) { - printf("NULL != \"\" !!!!\r\n"); - p = perm_malloc(1); - *p = '\0'; - return p; + if (m->list_id && (l1 = hash_lookup(lists, m->list_id)) && !l1->maillist) + output_membership(l1, out); + else + fputs(m->name, out); } - len = strlen(s) + 1; - p = perm_malloc((u_int)len); - if (p) memcpy(p, s, len); - return p; + if (!l->m) + fprintf(out, "/dev/null"); } -#define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size)) - -/* Create a hash table. The size is just a hint, not a maximum. */ - -struct hash *create_hash(size) -int size; +/* Write a word-wrapped list description to the aliases file as a + * comment. */ +void put_fill(FILE *aliases, char *string) { - struct hash *h; - - h = (struct hash *) perm_malloc(sizeof(struct hash)); - if (h == (struct hash *) NULL) - return((struct hash *) NULL); - h->size = size; - h->data = (struct bucket **) perm_malloc(size * sizeof(char *)); - if (h->data == (struct bucket **) NULL) { - return((struct hash *) NULL); - } - memset(h->data, 0, size * sizeof(char *)); - return(h); -} - -/* Lookup an object in the hash table. Returns the value associated with - * the key, or NULL (thus NULL is not a very good value to store...) - */ - -char *hash_lookup(h, key) -struct hash *h; -register int key; -{ - register struct bucket *b; - - b = h->data[hash_func(h, key)]; - while (b && b->key != key) - b = b->next; - if (b && b->key == key) - return(b->data); - else - return(NULL); -} - - -/* Update an existing object in the hash table. Returns 1 if the object - * existed, or 0 if not. - */ - -int hash_update(h, key, value) -struct hash *h; -register int key; -char *value; -{ - register struct bucket *b; - - b = h->data[hash_func(h, key)]; - while (b && b->key != key) - b = b->next; - if (b && b->key == key) { - b->data = value; - return(1); - } else - return(0); -} - + char *c; + int line_width; + int word_width; -/* Store an item in the hash table. Returns 0 if the key was not previously - * there, 1 if it was, or -1 if we ran out of memory. - */ + if (!string || !*string) + return; + fputs("# ", aliases); + line_width = 3; + + while (1) + { + while (*string == ' ') + string++; + c = strchr(string, ' '); + if (!c) + word_width = strlen(string); + else + { + word_width = c - string; + *c = '\0'; + } -int hash_store(h, key, value) -struct hash *h; -register int key; -char *value; -{ - register struct bucket *b, **p; - - p = &(h->data[hash_func(h, key)]); - if (*p == NULL) { - b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket)); - if (b == (struct bucket *) NULL) - return(-1); - b->next = NULL; - b->key = key; - b->data = value; - return(0); + if (line_width + word_width > MAX_LINE_WIDTH) + { + fputs("\n# ", aliases); + line_width = 3; + fputs(string, aliases); + } + else + fputs(string, aliases); + + if (!c) + break; + /* add a space after the word */ + fputc(' ', aliases); + word_width++; + line_width += word_width; + string += word_width; + /* add another if after a period */ + if (*--c == '.') + { + fputc(' ', aliases); + line_width++; + } } - for (b = *p; b && b->key != key; b = *p) - p = (struct bucket **) *p; - if (b && b->key == key) { - b->data = value; - return(1); - } - b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket)); - if (b == (struct bucket *) NULL) - return(-1); - b->next = NULL; - b->key = key; - b->data = value; - return(0); + fputc('\n', aliases); } -/* Search through the hash table for a given value. For each piece of - * data with that value, call the callback proc with the corresponding key. +/* Illegal chars: this no longer corresponds to the array + * in setup_alis. '+' is a valid character in a string on + * a list, but is not a valid character in a listname. */ -hash_search(h, value, callback) -struct hash *h; -register char *value; -void (*callback)(); -{ - register struct bucket *b, **p; - - for (p = &(h->data[h->size - 1]); p >= h->data; p--) { - for (b = *p; b; b = b->next) { - if (b->data == value) - (*callback)(b->key); - } - } -} - - -/* Step through the hash table, calling the callback proc with each key. - */ +static int illegalchars[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */ + 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; -hash_step(h, callback, hint) -struct hash *h; -void (*callback)(); -char *hint; +int check_string(char *s) { - register struct bucket *b, **p; + for (; *s; s++) + { + if (isupper(*s)) + *s = tolower(*s); - for (p = &(h->data[h->size - 1]); p >= h->data; p--) { - for (b = *p; b; b = b->next) { - (*callback)(b->key, b->data, hint); - } + if (illegalchars[(unsigned) *s]) + return 0; } + return 1; }