作者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;
}
--
□ 本文章由 itoc 從 pc512-2.EE.NCTU.edu.tw 發表