X-Git-Url: http://andersk.mit.edu/gitweb/moira.git/blobdiff_plain/dfaf9b689acdde6a56d3874ee14cd53d192bb4ae..e35622fc2ccc96373a383fe1550e1e5b17202d28:/gen/mailhub.pc diff --git a/gen/mailhub.pc b/gen/mailhub.pc index 96170459..6e531aa5 100644 --- a/gen/mailhub.pc +++ b/gen/mailhub.pc @@ -28,15 +28,13 @@ char *whoami = "mailhub.gen"; char *db = "moira/moira"; 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, *names; +struct hash *users, *machines, *strings, *lists; struct user { char *login; char *pobox; @@ -52,51 +50,32 @@ struct list { char *description; char acl_t; int acl_id; + char mailman; + char *mailman_server; struct member *m; }; -struct names { - char *name; - struct names *next; - int keep; - int id; -}; void get_info(void); -void save_mlist(int id, void *list, void *force); -void insert_login(int id, void *user, void *hint); -void insert_name(char *s, int id, int nodups, int copy); -int hashstr(char *s); -void sort_info(void); -void output_data(int dummy, void *names, void *out); -void output_mlist(int id, struct list *l); -void do_member(FILE *out, char *s); +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; + int main(int argc, char **argv) { - long tm = time(NULL); + time_t tm = time(NULL); char filename[MAXPATHLEN], *targetfile; - struct stat sb; - EXEC SQL BEGIN DECLARE SECTION; - int flag; - EXEC SQL END DECLARE SECTION; + FILE *out = stdout; + srand(tm); 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"))) @@ -119,11 +98,15 @@ int main(int argc, char **argv) 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); @@ -141,11 +124,11 @@ int main(int argc, char **argv) void get_info(void) { EXEC SQL BEGIN DECLARE SECTION; - int id, pid, bid, cnt, maillistp, acl, mid; + 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]; + char type[LIST_ACL_TYPE_SIZE], mailman_server[MACHINE_NAME_SIZE]; EXEC SQL END DECLARE SECTION; char *s; struct user *u; @@ -159,12 +142,15 @@ void get_info(void) EXEC SQL WHENEVER SQLERROR GOTO sqlerr; cnt = 0; - machines = create_hash(1000); + 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) @@ -218,29 +204,61 @@ void get_info(void) users = create_hash(13001); EXEC SQL DECLARE u_cursor CURSOR FOR - SELECT users_id, login, potype, pop_id, box_id + 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) { - EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :bid; + 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 (potype[0] == 'P' && (s = hash_lookup(machines, pid))) + if (!strcmp(strtrim(potype), "NONE")) + u->pobox = NULL; + else { - char *buf = malloc(strlen(u->login) + strlen(s) + 2); - sprintf(buf, "%s@%s", u->login, s); - u->pobox = buf; + /* 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; + } + + /* 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; + } + + if (pid && (s = hash_lookup(machines, pid))) + { + paddr = malloc(strlen(u->login) + strlen(s) + 2); + sprintf(paddr, "%s@%s", u->login, s); + } + + 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; } - else if (potype[0] == 'S') - u->pobox = hash_lookup(strings, bid); - else - u->pobox = NULL; + + check_string(u->login); if (hash_store(users, id, u) < 0) { fprintf(stderr, "Out of memory!\n"); @@ -255,14 +273,16 @@ void get_info(void) 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 + 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; + EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl, + :mailman, :mailman_server; if (sqlca.sqlcode) break; l = malloc(sizeof(struct list)); @@ -271,6 +291,8 @@ void get_info(void) 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) { @@ -333,266 +355,130 @@ sqlerr: } -void save_mlist(int id, void *list, void *force) -{ - struct member *m; - struct list *l = 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 = hash_lookup(lists, l->acl_id))) - save_mlist(0, l1, (void *)TRUE); - - for (m = l->m; m; m = m->next) - { - if (m->list_id && (l1 = hash_lookup(lists, m->list_id))) - save_mlist(0, l1, (void *)TRUE); - } -} - - -void insert_login(int id, void *user, void *hint) +void output_login(int dummy, void *user, void *out) { struct user *u = user; - if (u->pobox && u->login[0] != '#') - insert_name(u->login, id, TRUE, FALSE); -} - -int incount = 0; - -void insert_name(char *s, int id, int nodups, int copy) -{ - int code; - struct names *ns; incount++; - code = hashstr(s); - ns = hash_lookup(names, code); - if (!ns) - { - if (!(ns = malloc(sizeof(struct names)))) - { - fprintf(stderr, "ran out of memory inserting name (sorting)\n"); - exit(MR_NO_MEM); - } - if (copy) - ns->name = strdup(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); - } - return; - } - if (strcasecmp(ns->name, s)) - { - while (ns->next) - { - ns = ns->next; - if (!strcasecmp(ns->name, s)) - goto foundns; - } - if (!(ns->next = malloc(sizeof(struct names)))) - { - fprintf(stderr, "ran out of memory insterting name (sorting)\n"); - exit(MR_NO_MEM); - } - ns = ns->next; - if (copy) - ns->name = strdup(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; - } - ns->id = 0; + 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 }; -/* 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, -}; +void output_mlist(int id, void *list, void *out) +{ + struct list *l = list, *l1; + struct user *u; + int len = strlen(l->name), i; + if (!l->maillist || !check_string(l->name)) + return; -/* While hashing the string, punt any illegal characters */ + /* 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; -int hashstr(char *s) -{ - int result; - int c; + put_fill(out, l->description); - for (result = 0; (c = *s); s++) + if (l->mailman && strcmp(l->mailman_server, "[NONE]")) { - if (illegalchars[c]) - { - char *p; - for (p = s; *p; p++) - *p = p[1]; - continue; - } - if (isupper(c)) - c = *s = tolower(c); - result = (result << 5) - result + c - '`'; + 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); } - return result < 0 ? -result : result; -} - - -void sort_info(void) -{ - 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); -} - - -void output_data(int dummy, void *names, void *out) -{ - struct names *ns, *nms = names; - struct user *u; - - incount++; - for (ns = nms; ns; ns = ns->next) + else if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id))) { - if (!ns->name[0] || !ns->name[1]) - { - fprintf(stderr, "punting %s due to short name\n", ns->name); - continue; - } - if (ns->id > 0) + fprintf(out, "owner-%s: ", l->name); + if ((l1->maillist) && (strcmp(l->name, l1->name))) + fprintf(out, "%s\n", l1->name); + else { - u = hash_lookup(users, ns->id); - if (u->pobox) - fprintf(out, "%s: %s\n", ns->name, u->pobox); + alias_width = line_width = len + 8; + output_membership(l1, out); + fprintf(out, "\n"); } } -} - - -int lwid, bol, awid; - -void output_mlist(int id, struct list *l) -{ - struct list *l1; - struct member *m; - struct user *u; - - put_fill(out, l->description); - if (l->acl_t == 'L' && (l1 = 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 = 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); + fprintf(out, "owner-%s: %s\n", l->name, u->login); - lwid = strlen(l->name) + 2; - bol = 1; - for (m = l->m; m; m = m->next) - do_member(out, m->name); - if (!l->m) - fprintf(out, "/dev/null"); + fprintf(out, "%s: ", l->name); + alias_width = line_width = len + 2; + output_membership(l, out); fprintf(out, "\n\n"); incount++; } - -/* print out strings separated by commas, doing line breaks as appropriate */ - -void do_member(FILE *out, char *s) +void output_membership(struct list *l, FILE *out) { - int wwid; + struct member *m; + struct list *l1; + int word_width, linestart = 1; static int cont = 1; char str[8]; - wwid = strlen(s); - - if (!bol && awid + wwid + 2 > AL_MAX_WID) + for (m = l->m; m; m = m->next) { - 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; - } + word_width = strlen(m->name); - 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; + 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; + } + else if (linestart) + { + /* First word on line, so we can't wrap. */ + line_width += word_width; + alias_width = line_width; + linestart = 0; + } + 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); + } + + if (m->list_id && (l1 = hash_lookup(lists, m->list_id)) && !l1->maillist) + output_membership(l1, out); + else + fputs(m->name, out); } - lwid += wwid + 2; - fprintf(out, ", %s", s); + if (!l->m) + fprintf(out, "/dev/null"); } - +/* Write a word-wrapped list description to the aliases file as a + * comment. */ void put_fill(FILE *aliases, char *string) { char *c; - int lwid; - int wwid; + int line_width; + int word_width; if (!string || !*string) return; fputs("# ", aliases); - lwid = 3; + line_width = 3; while (1) { @@ -600,17 +486,17 @@ void put_fill(FILE *aliases, char *string) string++; c = strchr(string, ' '); if (!c) - wwid = strlen(string); + word_width = strlen(string); else { - wwid = c - string; + word_width = c - string; *c = '\0'; } - if ((lwid + wwid) > ML_WID) + if (line_width + word_width > MAX_LINE_WIDTH) { fputs("\n# ", aliases); - lwid = 3; + line_width = 3; fputs(string, aliases); } else @@ -620,14 +506,14 @@ void put_fill(FILE *aliases, char *string) break; /* add a space after the word */ fputc(' ', aliases); - wwid++; - lwid += wwid; - string += wwid; + word_width++; + line_width += word_width; + string += word_width; /* add another if after a period */ if (*--c == '.') { fputc(' ', aliases); - lwid++; + line_width++; } } @@ -635,10 +521,39 @@ void put_fill(FILE *aliases, char *string) } -void do_people(void) +/* 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. + */ + +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, +}; + +int check_string(char *s) { - 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); + for (; *s; s++) + { + if (isupper(*s)) + *s = tolower(*s); + + if (illegalchars[(unsigned) *s]) + return 0; + } + return 1; }