#include "bbs.h" int trans = 0; int partial = 0; int justified = 0; int regformed = 0; char * const str_space = " \t\n\r"; //////////////////////////////////////////////////////////////////////////// // Regform Utilities //////////////////////////////////////////////////////////////////////////// #define FN_REGFORM "regform" #define FN_REQLIST "reg.wait" // TODO define and use structure instead, even in reg request file. typedef struct { char userid[IDLEN+1]; char name [20]; char career[40]; char addr [50]; char phone [20]; } RegformEntry; // regform format utilities int load_regform_entry(RegformEntry *pre, FILE *fp) { char buf[STRLEN]; char *v; memset(pre, 0, sizeof(RegformEntry)); while (fgets(buf, sizeof(buf), fp)) { if (buf[0] == '-') break; buf[sizeof(buf)-1] = 0; v = strchr(buf, ':'); if (v == NULL) continue; *v++ = 0; if (*v == ' ') v++; chomp(v); if (strcmp(buf, "uid") == 0) strlcpy(pre->userid, v, sizeof(pre->userid)); else if (strcmp(buf, "name") == 0) strlcpy(pre->name, v, sizeof(pre->name)); else if (strcmp(buf, "career") == 0) strlcpy(pre->career, v, sizeof(pre->career)); else if (strcmp(buf, "addr") == 0) strlcpy(pre->addr, v, sizeof(pre->addr)); else if (strcmp(buf, "phone") == 0) strlcpy(pre->phone, v, sizeof(pre->phone)); } return pre->userid[0] ? 1 : 0; } int regfrm_load(const char *userid, RegformEntry *pre) { FILE *fp = NULL; char fn[PATHLEN]; int ret = 0; sethomefile(fn, userid, FN_REGFORM); if (!dashf(fn)) return 0; fp = fopen(fn, "rt"); if (!fp) return 0; ret = load_regform_entry(pre, fp); fclose(fp); return ret; } // working queue FILE * regq_init_pull() { FILE *fp = tmpfile(), *src =NULL; char buf[STRLEN]; if (!fp) return NULL; src = fopen(FN_REQLIST, "rt"); if (!src) { fclose(fp); return NULL; } while (fgets(buf, sizeof(buf), src)) fputs(buf, fp); fclose(src); rewind(fp); return fp; } int regq_pull(FILE *fp, char *uid) { char buf[STRLEN]; size_t idlen = 0; uid[0] = 0; if (fgets(buf, sizeof(buf), fp) == NULL) return 0; idlen = strcspn(buf, str_space); if (idlen < 1) return 0; if (idlen > IDLEN) idlen = IDLEN; strlcpy(uid, buf, idlen+1); return 1; } int regq_end_pull(FILE *fp) { // no need to unlink because fp is a tmpfile. if (!fp) return 0; fclose(fp); return 1; } void transform(userec_t *new, userec_t *old, int i) { char fn[1024]; char *s, *s2; memcpy(new, old, sizeof(userec_t)); // already converted? if (old->version == PASSWD_VERSION || !old->userid[0]) return; if (old->version != 2275 && old->userid[0]) { fprintf(stderr, "invalid record at %d: %s\n", i, old->userid); if (i == 1) memset(new, 0, sizeof(userec_t)); return; } // update version info new->version = PASSWD_VERSION; // zero out memset(new->career, 0, sizeof(new->career)); memset(new->phone, 0, sizeof(new->phone)); memset(new->chkpad0, 0, sizeof(new->chkpad0)); memset(new->chkpad1, 0, sizeof(new->chkpad1)); memset(new->chkpad2, 0, sizeof(new->chkpad2)); // quick skip if (!old->justify[0] || !old->userid[0]) return; printf("%s ", old->userid); printf("%s -> ", old->justify); s = old->justify; // process only if justify is truncated. while (strlen(old->justify) == sizeof(old->justify) -1) { RegformEntry re; // try regform first. if (regfrm_load(old->userid, &re)) { // trust the form. strlcpy(new->career, re.career, sizeof(new->career)); strlcpy(new->phone, re.phone, sizeof(new->phone)); // justify will be updated someday... throw it printf(" [%s][%s][%s]\n", new->career, new->phone, new->justify); regformed ++; trans++; return; } // try to build from ~/justify, if exists. sethomefile(fn, old->userid, "justify"); if (dashf(fn)) { FILE *fp = fopen(fn, "rt"); fn[0] = 0; fgets(fn, sizeof(fn), fp); fclose(fp); chomp(fn); if (strlen(fn) > strlen(s)) { char *xs; int quotes = 3; s = fn; // some justifies have multiple entries without \n... xs = s + strlen(s); while (quotes > 0 && xs > s) if (*--xs == ':') quotes--; if (xs > s) s = xs+1; justified ++; } } break; } // build career/phone s2 = strchr(s, ':'); if (s2) { *s2++ = 0; while (*s && !isdigit(*s) && *s != '(') s++; strlcpy(new->phone, s, sizeof(new->phone)); strlcpy(new->justify, s2, sizeof(new->justify)); s = s2; s2 = strchr(s, ':'); if (s2) { *s2++ = 0; } else if (new->userlevel & PERM_LOGINOK) { // skip non-loginOK users partial ++; printf(" "); } strlcpy(new->career, s, sizeof(new->career)); if (s2) strlcpy(new->justify, s2, sizeof(new->justify)); else strlcpy(new->justify, "", sizeof(new->justify)); } printf("[%s][%s][%s]\n", new->career, new->phone, new->justify); trans++; } int main(void) { int fd, fdw; userec_t new; userec_t old; int i = 0; printf("sizeof(userec_t)=%u\n", (unsigned int)sizeof(userec_t)); printf("You're going to convert your .PASSWDS\n"); printf("The new file will be named .PASSWDS.trans.tmp\n"); if (chdir(BBSHOME) < 0) { perror("chdir"); exit(-1); } if ((fd = open(FN_PASSWD, O_RDONLY)) < 0 || (fdw = open(FN_PASSWD".trans.tmp", O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0 ) { perror("open"); exit(-1); } while (read(fd, &old, sizeof(old)) > 0) { transform(&new, &old, ++i); write(fdw, &new, sizeof(new)); } close(fd); close(fdw); // TODO use FN_REQLIST to process other forms printf("total %d records translated (%d partial, %d justified, %d regformed).\n", trans, partial, justified, regformed); return 0; }