回精華區
作者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 */

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