回精華區
作者itoc, 信區: itoc
標題[功能] mail.c 信件自動轉寄到外站 Internet 信箱
時間06/03/31
作者: itoc (站上人數:802) 看板: plan
標題: [功能] 信件自動轉寄到外站 Internet 信箱
時間: 2006/03/31 Fri 09:23:38                           Updated: 2006/03/31

※ 引述《guessi.bbs@bbs.ee.ndhu.edu.tw (沒)》之銘言:
> 想寫一個功能"自動轉寄" 當使用者收取信件時自動轉寄到站外信箱 (類似於備份?)

  設定外部信箱

: global.h

#define FN_ACL          "acl"           /* 上站地點設定 */
+ #define FN_FORWARD    "forward"       /* 自動轉寄設定 */

: maple.p 加一行

+ int m_setforward(void);

: menu.c 適當的選單加入這選項

+ m_setforward, PERM_BASIC, M_SMAIL,
+ "AutoForward├ 自動轉寄 ┤",

: mail.c:m_setforward() 在 mail_hold() 後面新增這個函式

int
m_setforward()
{
  char fpath[64], ip[50];
  FILE *fp;

  usr_fpath(fpath, cuser.userid, FN_FORWARD);
  if (fp = fopen(fpath, "r"))
  {
    fscanf(fp, "%s", ip);
    fclose(fp);
  }
  else
  {
    ip[0] = '\0';
  }

  vget(b_lines - 1, 0, "請輸入信件自動轉寄的 E-mail:", ip, 50, GCARRY);

  if (ip[0] && !not_addr(ip) &&
    vans("確定開啟自動轉信功\能(Y/N)?[N] ") == 'y')
  {
    if (fp = fopen(fpath, "w"))
    {
      fprintf(fp, "%s", ip);
      fclose(fp);
      vmsg("設定完成");
      return XEASY;
    }
  }

  unlink(fpath);
  vmsg("取消自動轉寄或無效 E-mail");
  return XEASY;
}

> ───────────────────────────────────── <

  轉寄站內來信至外部信箱

: mail.c:forward_mail() 在 mail_send() 前面新增這個函式

/* cuser.userid 將「標題 title、檔案在 fpath」的信件寄給 userid 的外部信箱 */
static void
forward_mail(fpath, userid, title)
  char *fpath, *userid, *title;
{
  FILE *fp;
  char ip[80];

  usr_fpath(ip, userid, FN_FORWARD);
  if (fp = fopen(ip, "r"))
  {
    fscanf(fp, "%s", ip);
    fclose(fp);

    if (ip[0])
      bsmtp(fpath, title, ip, 0);
  }
}

: mail.c:mail_send()

    rec_add(folder, &hdr, sizeof(HDR));
+   forward_mail(fpath, rcpt, ve_title);

: mail.c:multi_send()

        rec_add(buf, &hdr, sizeof(HDR));
+       forward_mail(fpath, userid, title);

> ───────────────────────────────────── <

  轉寄站外來信至外部信箱

: bmtad.c:forward_mail() 在 bbs_mail() 前面新增這個函式

/* hdr->owner 將「標題 hdr->title、檔案在 folder 下 hdr->xname」
   的信件寄給 userid 的外部信箱 */

static void
forward_mail(hdr, folder, userid)
  HDR *hdr;
  char *folder;
  char *userid;
{
  FILE *fp;
  char ip[80], fpath[64];

  usr_fpath(ip, userid, FN_FORWARD);
  if (fp = fopen(ip, "r"))
  {
    fscanf(fp, "%s", ip);
    fclose(fp);

    if (ip[0])
    {
      hdr_fpath(fpath, folder, hdr);
      bbsmtp(fpath, hdr->title, ip, hdr->owner);
    }
  }
}

: bmtad.c:bbs_mail()

  rec_add(folder, &hdr, sizeof(HDR));
+ forward_mail(&hdr, folder, userid);

: bmtad.c:bbsmtp() 在 forward_mail() 前面新增這個函式

static int                              /* >=0:成功 <0:失敗 */
bbsmtp(fpath, title, rcpt, sender)      /* 從 bsmtp() 抄來的 */
  char *fpath, *title, *rcpt, *sender;
{
  int sock;
  time_t stamp;
  FILE *fp, *fr, *fw;
  char *str, buf[512], from[80], msgid[80];
  ACCT acct;

  if (acct_fetch(sender, &acct) < 0)
    return -1;

  time(&stamp);
  sprintf(from, "%s.bbs@%s", acct.userid, MYHOSTNAME);

  str = strchr(rcpt, '@') + 1;
  sock = dns_smtp(str);
  if (sock >= 0)
  {
    sleep(1);                   /* wait for mail server response */

    fr = fdopen(sock, "r");
    fw = fdopen(sock, "w");

    fgets(buf, sizeof(buf), fr);
    if (memcmp(buf, "220", 3))
      goto smtp_error;
    while (buf[3] == '-')
      fgets(buf, sizeof(buf), fr);

    fprintf(fw, "HELO %s\r\n", MYHOSTNAME);
    fflush(fw);
    do
    {
      fgets(buf, sizeof(buf), fr);
      if (memcmp(buf, "250", 3))
        goto smtp_error;
    } while (buf[3] == '-');

    fprintf(fw, "MAIL FROM:<%s>\r\n", from);
    fflush(fw);
    do
    {
      fgets(buf, sizeof(buf), fr);
      if (memcmp(buf, "250", 3))
        goto smtp_error;
    } while (buf[3] == '-');

    fprintf(fw, "RCPT TO:<%s>\r\n", rcpt);
    fflush(fw);
    do
    {
      fgets(buf, sizeof(buf), fr);
      if (memcmp(buf, "250", 3))
        goto smtp_error;
    } while (buf[3] == '-');

    fprintf(fw, "DATA\r\n", rcpt);
    fflush(fw);
    do
    {
      fgets(buf, sizeof(buf), fr);
      if (memcmp(buf, "354", 3))
        goto smtp_error;
    } while (buf[3] == '-');

    /* ------------------------------------------------- */
    /* begin of mail header                              */
    /* ------------------------------------------------- */

    archiv32(stamp, msgid);

    /* Thor.990125: 儘可能的像 RFC 822 及 sendmail 的作法, 免得別人不接:p */
    fprintf(fw, "From: \"%s\" <%s>\r\nTo: %s\r\n",
      acct.username, from, rcpt);
    /* itoc.030411: mail 輸出 RFC 2047 */
    output_rfc2047_qp(fw, "Subject: ", title, MYCHARSET, "\r\n");
    /* itoc.030323: mail 輸出 RFC 2045 */
    fprintf(fw, "X-Sender: %s (%s)\r\n"
      "Date: %s\r\nMessage-Id: <%s@%s>\r\n"
      "Mime-Version: 1.0\r\n"
      "Content-Type: %s; charset=%s\r\n"
      "Content-Transfer-Encoding: 8bit\r\n"
      "X-Disclaimer: [%s] 對本信內容恕不負責\r\n\r\n",
      acct.userid, acct.username,
      Atime(&stamp), msgid, MYHOSTNAME,
      "text/plain", MYCHARSET,
      str_site);

    /* ------------------------------------------------- */
    /* begin of mail body                                */
    /* ------------------------------------------------- */

    if (fp = fopen(fpath, "r"))
    {
      char *ptr;

      str = buf;
      *str++ = '.';
      while (fgets(str, sizeof(buf) - 3, fp))
      {
        if (ptr = strchr(str, '\n'))
        {
          *ptr++ = '\r';
          *ptr++ = '\n';
          *ptr = '\0';
        }
        fputs((*str == '.' ? buf : str), fw);
      }
      fclose(fp);
    }
#ifdef HAVE_SIGNED_MAIL
    if (!rec_get(FN_RUN_PRIVATE, buf, 8, 0))
    {
      time_t prichro;

      buf[8] = '\0';    /* Thor.990413: buf 用不到了,借來用用 */
      prichro = chrono32(buf);
      archiv32(str_hash(msgid, prichro), buf);
      fprintf(fw,"※ X-Sign: %s$%s %s\r\n",
        msgid, genpasswd(buf), Btime(&stamp));
    }
#endif
    fputs("\r\n.\r\n", fw);
    fflush(fw);

    fgets(buf, sizeof(buf), fr);
    if (memcmp(buf, "250", 3))
      goto smtp_error;

    fputs("QUIT\r\n", fw);
    fflush(fw);
    fclose(fw);
    fclose(fr);
    goto smtp_log;

smtp_error:

    /* itoc.041128.註解: 凡是走到這裡的,buf 是對方回覆的錯誤訊息 */
    fclose(fr);
    fclose(fw);
    sprintf(from, "\t%.70s\n", buf);
    sock = -1;
  }
  else
  {
    strcpy(from, "\tSMTP 連線失敗\n");
  }

smtp_log:

  /* --------------------------------------------------- */
  /* 記錄寄信                                            */
  /* --------------------------------------------------- */

  sprintf(buf, "%s %-13s%c> %s\n%s\t%s\n\t%s\n",
    Btime(&stamp), acct.userid, '-', rcpt,
    sock >= 0 ? "" : from, title, fpath);
  f_cat(FN_RUN_MAIL_LOG, buf);

  return sock;
}

--
□ 本文章由 itocitoc.Dorm11.NCTU.edu.tw 發表
精華選讀←離開[主題上]主題下(k)上篇(j)下篇S/a搜尋 G串列 TAB精華 ↑↓捲 Pg/Space翻