/* * reghml.c * * auto registrar for fml */ #include #include #include /* #define NO_KANJINAME */ #define RMAIL "/usr/sbin/sendmail" #define MAXCOL 256 #define E_FROM 1 #define E_MISS 2 #define E_ADDR 3 #define E_POST 4 #define E_CHAR 5 #define E_NAME 6 #define DO_NONE 0 #define DO_CONF 1 #define DO_POST 2 #define K_NAME "MlName" #define K_RET "Return" #define K_TO "To" #define K_FROM "From" #define K_FROM2 "From2" #define K_LNAME "LName" #define K_FNAME "FName" #define K_CONF "DoConfirm" #define K_POST "DoPost" #define VC_SMTP "!#$%&'*+-./=?@^`{|}~" #define VC_FML "#,-.:@" #define VC_URL "!$%&'()*+,-./:;=?@_~" #define iseuc(c) (((unsigned char)(c)) >= 0xa1 \ && ((unsigned char)(c)) <= 0xfe) #define iskna(c) (((unsigned char)(c)) >= 0xa1 \ && ((unsigned char)(c)) <= 0xdf) static int validstr(char *, char *); static void sanitputs(char *, FILE *); static void head(char *); static void framemes(char *); static void hiddenkey(char *, char *); static void returnbutton(void); static void returnurl(char *); static void error(int, char *, char *); static int hex2int(int); static char *decodeqp(char *, int); static void strstore(char *); static void getargs(void); static void kanjiputs(char *, FILE *); static void input(void); static void confirm(void); static void post(void); static char mlname[MAXCOL + 1] = ""; static char returl[MAXCOL + 1] = ""; static char toaddr[MAXCOL + 1] = ""; static char fromaddr[MAXCOL + 1] = ""; static char confirmaddr[MAXCOL + 1] = ""; static char firstname[MAXCOL + 1] = ""; static char lastname[MAXCOL + 1] = ""; static char *myname = NULL; static int action = DO_NONE; static unsigned short kanatbl[] = { 0x0000, 0x2123, 0x2156, 0x2157, 0x2122, 0x2126, 0x2572, 0x2521, 0x2523, 0x2525, 0x2527, 0x2529, 0x2563, 0x2565, 0x2567, 0x2543, 0x213c, 0x2522, 0x2524, 0x2526, 0x2528, 0x252a, 0x252b, 0x252d, 0x252f, 0x2531, 0x2533, 0x2535, 0x2537, 0x2539, 0x253b, 0x253d, 0x253f, 0x2541, 0x2544, 0x2546, 0x2548, 0x254a, 0x254b, 0x254c, 0x254d, 0x254e, 0x254f, 0x2552, 0x2555, 0x2558, 0x255b, 0x255e, 0x255f, 0x2560, 0x2561, 0x2562, 0x2564, 0x2566, 0x2568, 0x2569, 0x256a, 0x256b, 0x256c, 0x256d, 0x256f, 0x2573, 0x212b, 0x212c, }; static char version[] = "@(#)regfml.c 1.03 08/06/02"; static int validstr(s, valid) char *s, *valid; { int c; for (; *s; s++) { c = *((unsigned char *)s); if (c >= '0' && c <= '9') continue; if (c >= 'A' && c <= 'Z') continue; if (c >= 'a' && c <= 'z') continue; if (c == '_') continue; if (valid && strchr(valid, c)) continue; return(0); } return(1); } static void sanitputs(s, fp) char *s; FILE *fp; { int i; for (i = 0; s[i]; i++) switch (s[i]) { case '"': fputs(""", fp); break; case '&': fputs("&", fp); break; case '\'': fputs("'", fp); break; case '<': fputs("<", fp); break; case '>': fputs(">", fp); break; default: fputc(s[i], fp); break; } } static void head(s) char *s; { fputs("Content-Type: text/html; charset=EUC-JP\n", stdout); fputs("Content-Language: ja\n", stdout); fputc('\n', stdout); fputs("\n", stdout); fputs("\n", stdout); fputs("\n", stdout); fputs(" ", stdout); fputs(s, stdout); fputs("\n", stdout); fputs("\n", stdout); fputs("\n", stdout); fputs("

", stdout); if (*mlname) { sanitputs(mlname, stdout); fputc(' ', stdout); } fputs("ML 登録フォーム

\n", stdout); fputs("
\n\n", stdout); fputs("
\n", stdout); } static void framemes(s) char *s; { fputs("\n", stdout); fputs("\n", stdout); fputs("
", stdout); fputs(s, stdout); fputs("
\n\n", stdout); } static void hiddenkey(name, val) char *name, *val; { if (val && !*val) return; fputs("\n", stdout); } static void returnbutton(void) { fputs("
\n", stdout); hiddenkey(K_NAME, mlname); hiddenkey(K_RET, returl); hiddenkey(K_TO, toaddr); hiddenkey(K_FROM, fromaddr); hiddenkey(K_FROM2, confirmaddr); hiddenkey(K_LNAME, lastname); hiddenkey(K_FNAME, firstname); fputs("\n", stdout); fputs("
\n", stdout); } static void returnurl(s) char *s; { char *cp; int c; if (!(*returl) || !validstr(returl, VC_URL)) return; if (strncasecmp(returl, "http:", sizeof("http:") - 1) && strncasecmp(returl, "https:", sizeof("https:") - 1) && ((*returl >= 'A' && *returl <= 'Z') || (*returl >= 'a' && *returl <= 'z'))) { for (cp = returl + 1; *cp; cp++) { c = *((unsigned char *)cp); if (c >= '0' && c <= '9') continue; if (c >= 'A' && c <= 'Z') continue; if (c >= 'a' && c <= 'z') continue; if (c == '+' || c == '-' || c == '.') continue; if (*cp != ':') break; return; } } fputs(s, stdout); fputs("ここをクリックして下さい.\n", stdout); } static void error(n, s1, s2) int n; char *s1, *s2; { head("CGI 実行エラー"); switch (n) { case E_FROM: framemes("address が一致しません."); fputs("

\n", stdout); sanitputs(s1, stdout); fputs("
\n", stdout); sanitputs(s2, stdout); fputs("
\n", stdout); fputs("

\n", stdout); break; case E_MISS: framemes("入力項目が足りません."); break; case E_ADDR: framemes("不正なアドレス形式です."); fputs("

\n", stdout); sanitputs(s1, stdout); fputs("

\n", stdout); break; case E_POST: framemes("登録 mail の送信エラー."); fputs("

\n", stdout); sanitputs(s1, stdout); fputs("

\n", stdout); break; case E_CHAR: framemes("アドレスに使えない文字が使われています."); fputs("

\n", stdout); sanitputs(s1, stdout); fputs("

\n", stdout); break; #ifdef NO_KANJINAME case E_NAME: framemes("氏名に使えない文字が使われています. ローマ字で記入して下さい."); fputs("

\n", stdout); sanitputs(s1, stdout); fputs("

\n", stdout); break; #endif default: break; } fputs("\n

\n", stdout); fputs("「戻る」ボタンで入力画面に戻って入力し直して下さい.\n", stdout); returnbutton(); fputs("

\n", stdout); fputs("
\n", stdout); fputs("\n", stdout); fputs("\n", stdout); exit(1); } static int hex2int(c) int c; { if (c >= 'a' && c <= 'f') return(c - 'a' + 10); if (c >= 'A' && c <= 'F') return(c - 'A' + 10); if (c >= '0' && c <= '9') return(c - '0'); return(-1); } static char *decodeqp(s, len) char *s; int len; { int i, j, c1, c2, eq; for (i = j = eq = 0; i < len && s[i]; i++) { if (s[i] == '+') s[j++] = ' '; else if (s[i] != '%' || (c1 = hex2int(s[i + 1])) < 0 || (c2 = hex2int(s[i + 2])) < 0) { if (s[i] == '=') { if (eq) break; eq = 1; } s[j++] = s[i]; } else { c1 = c1 * 16 + c2; if (c1 == '=') eq = 1; s[j++] = c1; i += 2; } } s[j] = '\0'; return(s); } static void strstore(s) char *s; { char *cp; if (!(cp = strchr(s, '='))) return; *(cp++) = '\0'; if (!strcmp(s, K_NAME)) strcpy(mlname, cp); else if (!strcmp(s, K_RET)) strcpy(returl, cp); else if (!strcmp(s, K_TO)) strcpy(toaddr, cp); else if (!strcmp(s, K_FROM)) strcpy(fromaddr, cp); else if (!strcmp(s, K_FROM2)) strcpy(confirmaddr, cp); else if (!strcmp(s, K_LNAME)) strcpy(lastname, cp); else if (!strcmp(s, K_FNAME)) strcpy(firstname, cp); else if (!strcmp(s, K_CONF)) action = DO_CONF; else if (!strcmp(s, K_POST)) action = DO_POST; } static void getargs(void) { char *cp, *env, buf[MAXCOL + 1]; int i, j, c, len; if ((env = getenv("CONTENT_LENGTH")) && (len = atoi(env)) > 0) for (i = j = 0; ; i++) { c = (i < len) ? fgetc(stdin) : EOF; if (c != EOF && c != '&') { if (j < MAXCOL) buf[j++] = c; } else { decodeqp(buf, j); strstore(buf); j = 0; if (c == EOF) break; } } if (!(*toaddr)) error(E_MISS, NULL, NULL); if (!(cp = strchr(toaddr, '@')) || !strchr(++cp, '.')) error(E_ADDR, toaddr, NULL); if (!validstr(toaddr, VC_SMTP)) error(E_CHAR, toaddr, NULL); if (action == DO_NONE) return; if (!(*fromaddr) || !(*firstname) || !(*lastname)) error(E_MISS, NULL, NULL); #ifdef NO_KANJINAME if (!validstr(lastname, VC_FML)) error(E_NAME, lastname, NULL); if (!validstr(firstname, VC_FML)) error(E_NAME, firstname, NULL); #endif if (action == DO_CONF) { if (!(*confirmaddr)) error(E_MISS, NULL, NULL); if (strcmp(fromaddr, confirmaddr)) error(E_FROM, fromaddr, confirmaddr); } if (!(cp = strchr(fromaddr, '@')) || !strchr(++cp, '.')) error(E_ADDR, fromaddr, NULL); if (!validstr(fromaddr, VC_SMTP)) error(E_CHAR, fromaddr, NULL); } static void kanjiputs(s, fp) char *s; FILE *fp; { int i, n, kanji; /* Suppose EUC-JP */ kanji = 0; for (i = 0; s[i]; i++) { if ((unsigned char)(s[i]) == 0x8e && iskna(s[i + 1])) { n = (unsigned char)(s[i + 1]) - 0xa0; n = kanatbl[n]; if (!kanji) fputs("\033$B", fp); kanji = 1; fputc(n >> 8, fp); fputc(n & 0xff, fp); i++; } else if (iseuc(s[i]) && iseuc(s[i + 1])) { if (!kanji) fputs("\033$B", fp); kanji = 1; fputc((unsigned char)(s[i++]) & 0x7f, fp); fputc((unsigned char)(s[i]) & 0x7f, fp); } else if ((unsigned char)(s[i]) & 0x80) { if (kanji) fputs("\033(B", fp); kanji = 0; fputc('?', fp); } else { if (kanji) fputs("\033(B", fp); kanji = 0; fputc(s[i], fp); } } if (kanji) fputs("\033(B", fp); } static void input(void) { head("登録項目の入力"); framemes("ML に登録するために以下の必要項目を入力して下さい."); fputs("
\n", stdout); hiddenkey(K_CONF, NULL); hiddenkey(K_NAME, mlname); hiddenkey(K_RET, returl); hiddenkey(K_TO, toaddr); fputs("\n
\n", stdout); fputs("\n", stdout); fputs("\n", stdout); fputs("\n", stdout); fputs("\n", stdout); fputs("\n", stdout); fputs("\n", stdout); fputs("\n", stdout); fputs("\n", stdout); fputs("\n", stdout); fputs("\n", stdout); fputs("
配送先 E-Mail アドレス
\n", stdout); fputs("", stdout); fputs("確認のためもう一度
あなたの氏名\n", stdout); fputs("名", stdout); #ifdef NO_KANJINAME fputs("\n", stdout); fputs("ローマ字で記入して下さい", stdout); #endif fputs("
\n", stdout); fputs("\n", stdout); fputs("
\n", stdout); fputs("
\n", stdout); fputs("
\n", stdout); fputs("\n

\n", stdout); returnurl("登録をやめるには"); fputs("

\n", stdout); } static void confirm(void) { head("登録内容の確認"); framemes("以下の内容で ML 登録して構いませんか?"); fputs("
\n", stdout); hiddenkey(K_POST, NULL); hiddenkey(K_NAME, mlname); hiddenkey(K_RET, returl); hiddenkey(K_TO, toaddr); hiddenkey(K_FROM, fromaddr); hiddenkey(K_FROM2, confirmaddr); hiddenkey(K_LNAME, lastname); hiddenkey(K_FNAME, firstname); fputs("\n\n", stdout); fputs("\n\n", stdout); fputs("\n\n", stdout); fputs("\n", stdout); fputs("
配送先 E-Mail アドレス", stdout); sanitputs(fromaddr, stdout); fputs("
あなたの氏名", stdout); sanitputs(lastname, stdout); fputc(' ', stdout); sanitputs(firstname, stdout); fputs("
", stdout); fputs("
\n", stdout); fputs("
\n", stdout); fputs("\n

\n", stdout); fputs("内容に誤りのある場合は、\n", stdout); fputs("「戻る」ボタンで入力画面に戻って下さい.\n", stdout); returnbutton(); fputs("

\n", stdout); } static void post(void) { FILE *fp; char buf[MAXCOL + 1]; strcpy(buf, RMAIL); strcat(buf, " -f \""); strcat(buf, fromaddr); strcat(buf, "\" \""); strcat(buf, toaddr); strcat(buf, "\""); if (!(fp = popen(buf, "w"))) error(E_POST, RMAIL, NULL); fputs("To: ", fp); fputs(toaddr, fp); fputc('\n', fp); fputs("Subject: Auto subscribe to ML\n", fp); fputs("From: ", fp); fputs(fromaddr, fp); fputc('\n', fp); fputc('\n', fp); fputs("subscribe ", fp); kanjiputs(lastname, fp); fputc(' ', fp); kanjiputs(firstname, fp); fputc('\n', fp); if (pclose(fp)) error(E_POST, RMAIL, NULL); head("登録の完了"); framemes("ML への登録が完了しました."); fputs("

\n後ほど、\n", stdout); fputs("登録アドレス宛に確認 mail が届きますので、", stdout); fputs("その内容に従って返信して下さい.\n", stdout); fputs("

\n", stdout); returnurl("この画面から抜けるには"); fputs("", stdout); fputs("

\n", stdout); fputs("多重登録されてしまうので reload はしないで下さい.\n", stdout); fputs("\n", stdout); fputs("

\n", stdout); } int main(argc, argv) int argc; char *argv[]; { if (!(myname = strrchr(argv[0], '/'))) myname = argv[0]; else myname++; getargs(); switch (action) { case DO_CONF: confirm(); break; case DO_POST: post(); break; default: input(); break; } fputs("\n\n", stdout); fputs("\n", stdout); fputs("\n", stdout); return(0); }