作者itoc, 信區: itoc
標題[網路] grade.c 交通大學成績查詢
時間03/02/12
作者: itoc (AsPSQwel) 看板: plan
標題: [功能] grade.c 交大成績查詢
時間: Wed Feb 12 21:26:55 2003 Updated: 2003/12/29
: menu.c 在適當的選單加上
+ "bin/grade.so:main_grade", 0, - M_XMODE,
+ "Grade ♂ 成績查榜 ♀",
: game/Makefile
SO = ... grade.so
: game/grade.c 新增這程式
/*-------------------------------------------------------*/
/* grade.c ( NTHU CS MapleBBS Ver 3.10 ) */
/*-------------------------------------------------------*/
/* target : 交通大學查成績系統 */
/* create : 02/06/26 */
/* update : 02/07/26 */
/* author : eric.bbs@boring.twbbs.tw */
/* modify : itoc.bbs@bbs.tnfsh.tn.edu.tw */
/*-------------------------------------------------------*/
#include "bbs.h"
#ifdef HAVE_NETTOOL
#define mouts(x,y,s) { move(x, y); outs(s); }
#define HTTP_PORT 80
#define SERVER_grade "140.113.101.141"
#define CGI_grade "/REGCGI"
static char *
html_strip(p, c, len)
char *p, *c;
int len;
{
int i;
p += 4; /* <td> */
for (i = 0; *p != '<'; i++)
{
if (i < len)
*c++ = *p;
p++;
}
*c = '\0';
return p;
}
static int
http_conn(server, s, sid)
char *server, *s, *sid;
{
int sockfd, i;
int sum, sub, gpa, pass, nocount, graduate;
char *p, *xtail;
char pool[8192], fpath[64];
char cid[7], cname[31], cs[5], cscore[11], ct[2];
FILE *fp;
mouts(b_lines - 1, 0, "連接伺服器中,請稍候.............");
refresh();
if ((sockfd = dns_open(server, HTTP_PORT)) < 0)
{
vmsg("無法與伺服器取得連結,查詢失敗!");
return -1;
}
/* parser return message from web server */
write(sockfd, s, strlen(s));
/* read(sockfd, p = pool, sizeof(pool)); */ /* 太大了,一次讀不完 */
p = xtail = pool;
for (;;)
{
if (p >= xtail)
{
i = read(sockfd, p, sizeof(pool));
if (i <= 0)
break;
xtail = p + i;
}
p++;
}
shutdown(sockfd, 1);
close(sockfd);
sprintf(fpath, "tmp/%s.grade", cuser.userid);
fp = fopen(fpath, "w");
/* itoc.註解: 新生沒有歷年成績時,會因為 pool 還殘存前一個人的資料,
故顯示前一個人的成績或造成判斷錯誤,所以要先把最後一個(第二個)
</TABLE> 找出來 */
xtail = strstr(pool, "</TABLE>");
xtail = strstr(xtail + 1, "</TABLE>");/* 找最後一個 </TABLE> */
sum = 0; /* 加權總分 */
sub = 0; /* 修習的總學分 */
pass = 0; /* 及格的學分 */
nocount = 0; /* 不列入平均的學分 */
gpa = 0; /* 加權 GPA 總分 */
graduate = atoi(sid) % 1000 >= 200 ? 1 : 0; /* 研究生還是大學生 */
p = pool;
fputs(" ╭═══╦═══════════════╦══╦═════╦══╮\n", fp);
fputs(" ║課號 ║課名 ║學分║ 分數 ║選修║\n", fp);
fputs(" ╠═══╬═══════════════╬══╬═════╬══╣\n", fp);
for (;;)
{
p = strstr(p, "<td>");
if (!p || p >= xtail) /* 到最後了或新生根本沒資料 */
break;
p = html_strip(p, cid, 6); /* 課號 */
p = html_strip(p, cname, 30); /* 課名 */
p = html_strip(p, cs, 4); /* 學分 */
p = html_strip(p, cscore, 10); /* 分數 */
p = html_strip(p, ct, 1); /* 選別 */
fprintf(fp, " ║\033[35m%-6s\033[m║\033[33m%-30s\033[m║"
"\033[32m%-4s\033[m║\033[36m%-10s\033[m║\033[31m%-4s\033[m║\n",
cid, cname, cs, cscore, ct);
if (!str_ncmp(cscore, "成績未送達", 10) || !str_ncmp(cscore, "Tr", 2)) /* 抵免、成績未送達暫不算入平均、學分 */
{
continue;
}
else if (!str_ncmp(cscore, "Withdraw", 8)) /* Withdraw 不算入平均 */
{
i = atoi(cs);
nocount += i;
sub += i;
}
else if (!str_ncmp(cscore, "Pass", 4)) /* Pass 不算入平均 */
{
i = atoi(cs);
pass += i;
nocount += i;
sub += i;
}
else /* 有成績 */
{
i = atoi(cs);
sockfd = atoi(cscore);
sum += sockfd * i; /* 按學分加權 */
sub += i;
if (sockfd >= (graduate ? 70 : 60)) /* 研究生 70 分及格;大學生 60 分及格 */
{
pass += i;
if (graduate)
gpa += i * (sockfd >= 85 ? 4 : sockfd >= 75 ? 3 : 2);
else
gpa += i * (sockfd >= 80 ? 4 : sockfd >= 70 ? 3 : 2);
}
}
}
fputs(" ╰═══╩═══════════════╩══╩═════╩══╯\n", fp);
i = sub - nocount;
fprintf(fp, "\n 【平均】\033[1;31m%.2f\033[m 【學分】%d/%d 【GPA】%.2f\n",
i ? sum / (double) i : 0,
pass, sub,
i ? gpa / (double) i : 0); /* 避免除數為 0 */
fclose(fp);
if (more(fpath, (char *) -1) >= 0)
{
if (vans("您要將查詢結果寄回信箱嗎?[N] ") == 'y')
mail_self(fpath, cuser.userid, "[備 忘 錄] 成績查詢", 0);
}
unlink(fpath);
return 0;
}
static int
grade(sid, id, choice)
char *sid, *id;
int choice;
{
char pool[1024];
char atrn[256], sendform[512], serid[80], *p;
int sockfd, i;
if ((sockfd = dns_open(SERVER_grade, HTTP_PORT)) < 0)
{
vmsg("無法與伺服器取得連結,查詢失敗!");
return -1;
}
else
{
mouts(b_lines - 1, 0, "連接伺服器中,請稍候.............");
refresh();
}
sprintf(atrn, "F=CHKPASS&CHKKIND=2&userid=%s&passwd=%s", sid, id);
sprintf(sendform, "GET /regcgi?%s HTTP/1.0\n\n", atrn);
write(sockfd, sendform, strlen(sendform));
/* parse */
read(sockfd, pool, sizeof(pool));
close(sockfd);
/* itoc.註解: 不能用有沒有 strstr(pool, "SERID") 來檢查。
當前一個人正確輸入查詢時,會從 sockfd 中讀出較長的資料進 pool,
後一個人若輸入錯誤,會從 sockfd 中讀出較短的資料進 pool,
因為 pool 沒有清空,後一個人的 pool 後段中仍然會有前一個人的 SERID,
後一個人就會誤查到前一個人的成績 */
if (strstr(pool, "<b>"))
{
vmsg("查無此學號或密碼輸入錯誤,請重新輸入!");
return 0;
}
if (p = strstr(pool, "SERID"))
{
p = p + 14;
for (i = 0;; i++)
{
serid[i] = p[i];
if (p[i] == '"')
{
serid[i] = 0;
break;
}
}
}
sprintf(atrn, "F=SHOWSCORE&SERID=%s&USERID=%s%%20%%20%%20&CHOICE=%s",
serid, sid, choice ? "2.查詢歷年成績" : "1.查詢本學期成績");
sprintf(sendform, "GET /REGCGI?%s HTTP/1.0\n\n", atrn);
http_conn(SERVER_grade, sendform, sid);
return 0;
}
int
main_grade()
{
char sid[8]; /* 學號 */
char id[11]; /* 身分證字號 */
char ans[3];
int choice; /* 0:學期成績 1:歷屆成績 */
while (1)
{
clear();
mouts(0, 25, "\033[1;37;44m◎ 交通大學成績查詢 ◎\033[m");
mouts(3, 0, "資料來源:http://"SERVER_grade);
if (!vget(5, 0, "請輸入學號:", sid, 8, DOECHO))
break;
if (!vget(6, 0, "請輸入身分證字號:", id, 11, NOECHO))
break;
choice = vget(7,0, "請選擇 (1)本學期成績 (2)歷年成績:[1] ",
ans, 3, DOECHO) == '2';
grade(sid, id, choice);
}
return 0;
}
#endif /* HAVE_NETTOOL */
--
□ 本文章由 itoc 從 itoc.Dorm-GD2.NCTU.edu.tw 發表