回精華區
作者itoc (cygreadline4.dll), 信區: plan
標題[功能] 交大校園活動公告
時間2004/05/20 Thu 16:23:55 Updated: 2004/08/17
  交大校園活動公告 http://info.nctu.edu.tw/news/
  自動轉貼到 BBS 上的 [NCTU_news] 板
  (當然,要先開這個板;如果想換板名,程式裡面也要改)

: crontab -e 加入這二行

# 每天抓二次交大校園公告
20 10,14 * * * * bin/NCTUnews > /dev/null 2>&1

: src/util/Makefile

EXE =   ... NCTUnews

: src/util/NCTUnews.c 新增此程式

/*-------------------------------------------------------*/
/* util/NCTUnews.c       ( NTHU CS MapleBBS Ver 3.10 )   */
/*-------------------------------------------------------*/
/* target : 交大校園活動公告                             */
/* create : 04/05/20                                     */
/* update :   /  /                                       */
/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw                 */
/*-------------------------------------------------------*/


#include "bbs.h"


#define LYNX_PATH       "/usr/local/bin/lynx --source"  /* lynx 的絕對路徑 */


/*-------------------------------------------------------*/
/* BRD shm 部分須與 cache.c 相容                         */
/*-------------------------------------------------------*/


static BCACHE *bshm;

static void
init_bshm()
{
  /* itoc.030727: 在開啟 bbsd 之前,應該就要執行過 account,
     所以 bshm 應該已設定好 */

  bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE));

  if (bshm->uptime <= 0)        /* bshm 未設定完成 */
    exit(0);
}


static void
update_btime(brdname)
  char *brdname;
{
  BRD *bhdr, *tail;

  bhdr = bshm->bcache;
  tail = bhdr + bshm->number;
  do
  {
    if (!str_cmp(brdname, bhdr->brdname))
    {
      bhdr->btime = -1;
      break;
    }
  } while (++bhdr < tail);
}


/*-------------------------------------------------------*/
/* 發文到看板                                            */
/*-------------------------------------------------------*/


static char *Brdname = "NCTU_news";     /* 欲 post 的看板 */
static char *Userid = "交大校園公告";   /* 作者 */
static char *Username = "聯合服務中心"; /* 暱稱 */


static void
new_post(fpath, title)           /* 發文到看板 */
  char *fpath;          /* 檔案路徑 */
  char *title;          /* 文章標題 */
{
  HDR hdr;
  char folder[64];

  brd_fpath(folder, Brdname, FN_DIR);
  hdr_stamp(folder, HDR_LINK | 'A', &hdr, fpath);
  strcpy(hdr.owner, Userid);
  strcpy(hdr.nick, Username);
  strcpy(hdr.title, title);
  rec_add(folder, &hdr, sizeof(HDR));

  update_btime(Brdname);
}


/*-------------------------------------------------------*/
/* 抓網頁                                                */
/*-------------------------------------------------------*/


static int wlen;    /* 本行有多少字 */
static int slen;    /* 本行有多少半型字 */


static void
foutc(ch, fp)
  int ch;
  FILE *fp;
{
  static int in_tag = 0;    /* 1: 在 <tag> 中 */
  static int in_chi = 0;    /* 1: 前一碼是中文字 */

  if (ch == '<')
  {
    in_tag = 1;
    return;
  }

  /* 跳過 \t */
  if (ch == '\t')
    return;

  if (!in_tag)
  {
    if (in_chi)         /* 前一個char是中文字的第一碼 */
      in_chi = 0;
    else if (ch & 0x80)     /* 前一個char不是中文字的第一碼, */
      in_chi = 1;           /* 檢查這char是否為中文字的第一碼 */
    else            /* 如果都不是,表示這char是半型字 */
      slen++;

    if (wlen >= 60 - slen % 2)  /* 一行最多 60 字,若有奇數個半型字,*/
    {                           /* 該行只印 59 字 */
      fputs("\n    ", fp);  /* 每行前面都空四格 */
      wlen = 0;
      /* slen = 0; */
      slen = !in_chi;       /* 若新的這行第一個char是半型字,slen=1 */
    }

    fputc(ch, fp);
    wlen++;
  }
  else
  {
    if (ch == '>')
      in_tag = 0;
  }
}


static void
fouts(str, fp)
  uschar *str;
  FILE *fp;
{
  int ch;

  wlen = 0;
  slen = 0;
  fputs("\n    ", fp);      /* 每行前面都空四格 */

  while (ch = *str)
  {
    foutc(ch, fp);
    str++;
  }
}


static void
strip_title(str, title)
  uschar *str, *title;
{
  int ch, len = 0;
  uschar *dst;

  /* 去掉 str 中的 \t 及最後的 <tag>,存在 title */

  dst = title;
  while (ch = *str++)
  {
    if (ch == '<')
      break;

    if (ch != '\t')
    {
      *dst++ = ch;
      if (++len > 60)
        break;
    }
  }
  *dst = '\0';
}


static void
html_download(actno)          /* 下載文章並轉換為文字檔 */
  int actno;
{
  char link[128], title[TTLEN + 1];
  char buf[2048];       /* 假設文章每段不會超過 2048 字 */
  char *fsrc = "tmp/NCTUnews.src";
  char *fdst = "tmp/NCTUnews.dst";
  FILE *fpr, *fpw;
  int mode;
  char *ptr;

  /* 下載文章 */
  sprintf(link, "http://info.nctu.edu.tw/news/show_news.php?act_no=%d", actno);
  sprintf(buf, LYNX_PATH " %s > %s", link, fsrc);
  system(buf);

  /* 轉換為文字檔 */
  if (fpr = fopen(fsrc, "r"))
  {
    if (fpw = fopen(fdst, "w"))
    {
      /* 開頭加上檔頭 */
      while (fgets(buf, sizeof(buf), fpr))
      {
        /* <font size="2"> 的下一行就是標題 */
        if (strstr(buf, "<font size=\"2\">"))
        {
          if (fgets(buf, sizeof(buf), fpr))
          {
            strip_title(buf, title);

            fprintf(fpw, "%s %s (%s) %s %s\n",
              STR_AUTHOR1, Userid, Username, STR_POST2, Brdname);
            fprintf(fpw, "標題: %s\n時間: %s\n\n", title, Now());
          }
          break;
        }
      }

      /* 內容 */
      mode = 0;    /* 0:未開始  1:印到一半  2:結束 */
      while (fgets(buf, sizeof(buf), fpr))
      {
        if (ptr = strstr(buf, "<hr>"))
        {
          *ptr = '\0';
          mode++;

          if (mode == 1)  /* 第一次出現 <hr> 無內文 */
            continue;
        }

        if (mode)
        {
          fouts(buf, fpw);
          if (mode == 2)
            break;
        }
      }

      /* 結尾加上來源 */
      fprintf(fpw, "\n--\nNCTU! 交通大學校園活動公告\n%s\n", link);
      fclose(fpw);

      if (title[0])     /* 若無標題,也許是被刪除了 */
        new_post(fdst, title);
      unlink(fdst);
    }
    unlink(fsrc);
  }
}


/*-------------------------------------------------------*/
/* 主程式                                                */
/*-------------------------------------------------------*/


static int
urhigh_query()
{
  char *ftmp = "tmp/NCTUnews.tmp";
  char buf[512];       /* 假設每行不會超過 512 字 */
  char *ptr;
  FILE *fp;
  int high;

  high = 0;
  sprintf(buf, LYNX_PATH " http://info.nctu.edu.tw/news/list.php > %s", ftmp);
  system(buf);

  if (fp = fopen(ftmp, "r"))
  {
    while (fgets(buf, sizeof(buf), fp))
    {
      if (ptr = strstr(buf, "show_news.php?act_no="))
      {
        high = atoi(ptr + 21);
        break;
      }
    }

    fclose(fp);
    unlink(ftmp);
  }
  return high;
}


int
main()
{
  FILE *fp;
  int myhigh, urhigh;
  char buf[10];

  chdir(BBSHOME);

  /* 看自己抓到第幾篇了 */
  myhigh = 0;
  if (fp = fopen("run/NCTUnews", "r"))
  {
    fscanf(fp, "%8s", buf);
    fclose(fp);

    if ((urhigh = atoi(buf)) > 0)
      myhigh = urhigh;
  }

  /* 看聯合服務中心最新的有幾篇 */
  urhigh = urhigh_query();

  if (!myhigh)           /* 如果自己沒有篇數計數器,那就抓最後三篇 */
    myhigh = urhigh - 3;

  if (myhigh >= urhigh)  /* 沒有新公告 */
    return 0;

  init_bshm();

  /* 去抓新的公告 */
  for (myhigh++; myhigh <= urhigh; myhigh++)
    html_download(myhigh);

  /* 更新自己的篇數計數器 */
  if (fp = fopen("run/NCTUnews", "w"))
  {
    fprintf(fp, "%d", urhigh);
    fclose(fp);
  }

  return 0;
}

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