精華區beta SetupBBS 關於我們 聯絡資訊
/*-------------------------------------------------------*/ /* vote.c ( NTHU CS MapleBBS Ver 2.36 ) */ /*-------------------------------------------------------*/ /* target : boards' vote routines */ /* create : 95/03/29 */ /* update : 95/12/15 */ /*-------------------------------------------------------*/ #include "bbs.h" #include <time.h> long atol(); extern cmpbnames(); extern int numboards; extern void friend_edit(int type); static char STR_bv_control[] = "control"; /* 投票日期 選項 */ static char STR_bv_desc[] = "desc"; /* 投票目的 */ static char STR_bv_ballots[] = "ballots"; static char STR_bv_results[] = "results"; static char STR_bv_flags[] = "flags"; static char STR_bv_tickets[] = "tickets"; /* 一人幾票 */ static char STR_bv_comments[] = "comments"; /* 投票者的建意 */ static char STR_bv_limited[] = "limited"; /* 私人投票 */ enum {STRIP_ALL,STRIP_MOVE}; int strip_ansi(buf, str ,mode) char *buf, *str; int mode; { register int ansi,count=0; for (ansi = 0;*str /*&& *str != '\n' */; str++) { if (*str == 27) { ansi = 1; } else if (ansi) { if (!strchr("[01234567;", *str)) { if(mode && (*str=='m' || *str=='*')) { str--; for(;*str && strchr("[01234567;", *str) ;str--); if(buf) *buf++ = ''; } ansi = 0; } } else { if(buf) *buf++ = *str; count++; } } if(buf) *buf = '\0'; return count; } void b_suckinfile(fp, fname) FILE *fp; char *fname; { FILE *sfp; if (sfp = fopen(fname, "r")) { char inbuf[256]; while (fgets(inbuf, sizeof(inbuf), sfp)) fputs(inbuf, fp); fclose(sfp); } } int b_closepolls() { static char *fn_vote_polling = ".voting"; boardheader fh; struct stat st; FILE *cfp; char buf[80]; time_t now; int fd, dirty; now = time(NULL); if (stat(fn_vote_polling, &st) == -1 || st.st_mtime > now - 3600) return 0; if ((cfp = fopen(fn_vote_polling, "w")) == NULL) return 0; fprintf(cfp, ctime(&now)); fclose(cfp); resolve_boards(); if ((fd = open(fn_board, O_RDWR)) == -1) { outs(ERR_BOARD_OPEN); return -1; } flock(fd, LOCK_EX); dirty = 0; while (read(fd, &fh, sizeof(fh)) == sizeof(fh)) { if (fh.bvote && b_close(&fh)) { lseek(fd, sizeof(fh) * (getbnum(fh.brdname) - 1), SEEK_SET); if (write(fd, &fh, sizeof(fh)) != sizeof(fh)) { sprintf(currmsg, "Warning!"); kill(currpid, SIGUSR2); igetch(); break; } dirty = 1; } } if (dirty) /* vote flag changed */ touch_boards(); flock(fd, LOCK_UN); close(fd); return 0; } void vote_report(bname, fname, fpath) char *bname, *fname, *fpath; { register char *ip; time_t dtime; int fd; fileheader header; ip = fpath; while (*(++ip)); *ip++ = '/'; /* get a filename by timestamp */ dtime = time(0); for (;;) { sprintf(ip, "M%X", dtime & 03777777 ); fd = open(fpath, O_CREAT | O_EXCL | O_WRONLY, 0644); if (fd >= 0) break; dtime++; } close(fd); log_usies("TESTfn",fname); log_usies("TESTfp",fpath); unlink(fpath); link(fname, fpath); /* append record to .DIR */ memset(&header, 0, sizeof(fileheader)); strcpy(header.owner,"[馬路探子]"); sprintf(header.title, "[%s] 看板 選情報導", bname); { register struct tm *ptime = localtime(&dtime); sprintf(header.date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday); } strcpy(header.filename, ip); strcpy(ip, ".DIR"); if ((fd = open(fpath, O_WRONLY | O_CREAT, 0644)) >= 0) { flock(fd, LOCK_EX); lseek(fd, 0, SEEK_END); write(fd, &header, sizeof(fileheader)); flock(fd, LOCK_UN); close(fd); } } int b_close(fh) boardheader *fh; { FILE *cfp, *tfp, *frp; char *bname = fh->brdname; char buf[STRLEN]; char inchar, inbuf[80]; int counts[31], fd; int total, num ,bid; char b_control[64]; char b_newresults[64]; char b_report[64]; time_t now; struct stat st; now = time(NULL); if (fh->bvote == 2) { if (fh->vtime < now - 7 * 86400) { fh->bvote = 0; return 1; } else return 0; } if (fh->vtime > now) return 0; fh->bvote = 2; setbfile(b_control, bname, STR_bv_control); if (stat(b_control, &st) == -1) { fh->bvote = 0; return 1; } memset(counts, 0, sizeof(counts)); setbfile(buf, bname, STR_bv_flags); unlink(buf); setbfile(buf, bname, STR_bv_tickets); unlink(buf); setbfile(buf, bname, STR_bv_ballots); if ((fd = open(buf, O_RDONLY)) != -1) { while (read(fd, &inchar, 1) == 1) counts[(int) (inchar - 'A')]++; close(fd); } unlink(buf); setbfile(b_newresults, bname, "newresults"); if ((tfp = fopen(b_newresults, "w")) == NULL) return 1; fprintf(tfp, "%s\n◆ 投票中止於: %s\n◆ 票選題目描述:\n\n", msg_seperator, ctime(&fh->vtime)); setbfile(buf, bname, STR_bv_desc); b_suckinfile(tfp, buf); unlink(buf); fprintf(tfp, "\n◆ 投票結果:\n\n"); total = 0; if (cfp = fopen(b_control, "r")) { fgets(inbuf, sizeof(inbuf), cfp); while (fgets(inbuf, sizeof(inbuf), cfp)) { inbuf[(strlen(inbuf) - 1)] = '\0'; inbuf[43] = '\0'; /* truncate */ num = counts[inbuf[0] - 'A']; fprintf(tfp, " %-42s%3d 票\n", inbuf + 3, num); total += num; } fclose(cfp); } unlink(b_control); fprintf(tfp, "\n◆ 使用者建議:\n"); setbfile(buf, bname, STR_bv_comments); b_suckinfile(tfp, buf); unlink(buf); fprintf(tfp, "\n◆ 總票數 = %d 票\n\n", total); fclose(tfp); setbfile(b_report, bname, "report"); if(frp = fopen(b_report, "w")){ b_suckinfile(frp, b_newresults); fclose(frp); } sprintf(inbuf,"boards/%s",bname); vote_report(bname, b_report, inbuf); if(!belong("etc/NoStatBoards",bname)) { sprintf(inbuf,"boards/%s","Record"); vote_report(bname, b_report, inbuf); } unlink(b_report); tfp = fopen(b_newresults, "a"); setbfile(buf, bname, STR_bv_results); b_suckinfile(tfp, buf); fclose(tfp); Rename(b_newresults, buf); return 1; } int vote_maintain(bname) char *bname; { FILE *fp, *tick; char inbuf[STRLEN], buf[STRLEN]; int num = 0, aborted, tickets; time_t closetime; int pos; boardheader fh; char genbuf[4]; if (!(currmode & MODE_BOARD)) return 0; stand_title("舉辦投票"); setbfile(buf, bname, STR_bv_control); if ((fp = fopen(buf, "r"))) { int counts[31], fd, total, count = 0; char inchar; fgets(inbuf, sizeof(inbuf), fp); closetime = (time_t) atol(inbuf); prints("同時間內無法舉行兩個以上的投票。\n此次投票預計結束於: %s", ctime(&closetime)); memset(counts, 0, sizeof(counts)); setbfile(buf, bname, STR_bv_ballots); if ((fd = open(buf, O_RDONLY)) != -1) { while (read(fd, &inchar, 1) == 1) counts[(int) (inchar - 'A')]++; close(fd); } outs("\n◆ 預知投票紀事:\n\n"); total = 0; while (fgets(inbuf, sizeof(inbuf), fp)) { inbuf[(strlen(inbuf) - 1)] = '\0'; inbuf[43] = '\0'; /* truncate */ num = counts[inbuf[0] - 'A']; count++; move(((count-1)%15)+4,((count-1)/15)*40); prints(" %-31s%3d 票", inbuf, num); total += num; } fclose(fp); move(b_lines-2, 0); prints("\n◆ 目前總票數 = %d 票", total); getdata(b_lines - 1, 0, "(A)取消投票 (B)提早開票 (C)繼續?[C] ", genbuf, 4, LCECHO, 0); if (genbuf[0] == 'a') { setbfile(buf, bname, STR_bv_tickets); unlink(buf); setbfile(buf, bname, STR_bv_control); unlink(buf); setbfile(buf, bname, STR_bv_flags); unlink(buf); setbfile(buf, bname, STR_bv_ballots); unlink(buf); setbfile(buf, bname, STR_bv_desc); unlink(buf); setbfile(buf, bname, STR_bv_limited); unlink(buf); pos = search_record(fn_board, &fh, sizeof(fh), cmpbnames, (int) bname); fh.bvote = 0; if (substitute_record(fn_board, &fh, sizeof(fh), pos) == -1) outs(err_board_update); touch_boards(); /* vote flag changed */ resolve_boards(); } else if (genbuf[0] == 'b') { char b_newresults[80]; char b_report[80]; FILE *tfp, *frp; setbfile(b_newresults, bname, "newresults"); tfp = fopen(b_newresults, "w"); fprintf(tfp, "%s\n◆ 投票中止於: %s\n◆ 票選題目描述:\n\n", msg_seperator, ctime(&closetime)); setbfile(buf, bname, STR_bv_tickets); unlink(buf); setbfile(buf, bname, STR_bv_flags); unlink(buf); setbfile(buf, bname, STR_bv_ballots); unlink(buf); setbfile(buf, bname, STR_bv_desc); b_suckinfile(tfp, buf); unlink(buf); setbfile(buf, bname, STR_bv_limited); unlink(buf); fprintf(tfp, "◆ 投票結果:\n\n"); total = 0; setbfile(buf, bname, STR_bv_control); if (fp = fopen(buf, "r")) { fgets(inbuf, sizeof(inbuf), fp); while (fgets(inbuf, sizeof(inbuf), fp)) { inbuf[(strlen(inbuf) - 1)] = '\0'; inbuf[43] = '\0'; /* truncate */ num = counts[inbuf[0] - 'A']; fprintf(tfp, " %-42s%3d 票\n", inbuf + 3, num); total += num; } fclose(fp); } unlink(buf); fprintf(tfp, "\n◆ 使用者建議:\n"); setbfile(buf, bname, STR_bv_comments); b_suckinfile(tfp, buf); unlink(buf); fprintf(tfp, "\n◆ 總票數 = %d 票\n\n", total); fclose(tfp); setbfile(b_report, bname, "report"); if(frp = fopen(b_report, "w")){ b_suckinfile(frp, b_newresults); fclose(frp); } sprintf(inbuf,"boards/%s",bname); vote_report(bname, b_report, inbuf); if(!belong("etc/NoStatBoards",bname)) { sprintf(inbuf,"boards/%s","Record"); vote_report(bname, b_report, inbuf); } unlink(b_report); tfp = fopen(b_newresults, "a"); setbfile(buf, bname, STR_bv_results); b_suckinfile(tfp, buf); fclose(tfp); Rename(b_newresults, buf); pos = search_record(fn_board, &fh, sizeof(fh), cmpbnames, (int) bname); fh.bvote = 2; if (substitute_record(fn_board, &fh, sizeof(fh), pos) == -1) outs(err_board_update); touch_boards(); /* vote flag changed */ resolve_boards(); } return FULLUPDATE; } outs("按任何鍵開始編輯此次 [投票宗旨]:"); igetch(); setbfile(buf, bname, STR_bv_desc); aborted = vedit(buf, NA); if (aborted== -1) { clear(); outs("取消此次投票"); pressanykey(); return FULLUPDATE; } aborted = 0; setbfile(buf, bname, STR_bv_flags); unlink(buf); getdata(4, 0, "是否限定投票者名單:\ (y)編籍可投票人員名單 [N]任何人皆可投票 ?", inbuf, 2, LCECHO, 0); setbfile(buf, bname, STR_bv_limited); if(inbuf[0] == 'y') { fp=fopen (buf,"w"); fprintf(fp,"此次投票設限"); fclose(fp); friend_edit(FRIEND_CANVOTE); } else { if (dashf(buf)) unlink(buf); } clear(); getdata(0, 0, "此次投票進行幾天 (至少1天)?", inbuf, 4, DOECHO, 0); if (*inbuf == '\n' || !strcmp(inbuf, "0") || *inbuf == '\0') strcpy(inbuf, "1"); time(&closetime); closetime += atol(inbuf) * 86400; setbfile(buf, bname, STR_bv_control); fp = fopen(buf, "w"); fprintf(fp, "%lu\n", closetime); fflush(fp); clear(); outs("\n請依序輸入選項, 按 ENTER 完成設定"); num = 0; while (!aborted) { sprintf(buf, "%c) ", num + 'A'); getdata( (num%15) + 2,(num/15)*40, buf, inbuf, 36, DOECHO, 0); if (*inbuf) { fprintf(fp, "%1c) %s\n", (num+'A'), inbuf); num++; } if (*inbuf == '\0' || num == 30) aborted = 1; } fclose(fp); if(num==0) { clear(); setbfile(buf, bname, STR_bv_control); unlink(buf); prints( "取消此次投票\n" ); pressanykey(); return FULLUPDATE; } else { pos = search_record(fn_board, &fh, sizeof(fh), cmpbnames, (int) bname); fh.bvote = 1; fh.vtime = closetime; if (substitute_record(fn_board, &fh, sizeof(fh), pos) == -1) outs(err_board_update); touch_boards(); /* vote flag changed */ #ifdef HAVE_REPORT b_report("OPEN"); #endif while(1) { move( t_lines - 3, 0); sprintf(buf,"請問可以投幾票 (1~%1d): ",num); getdata(t_lines-3, 0, buf , inbuf, 3, DOECHO, 0); if(atoi(inbuf)<=0 ||atoi(inbuf)>num) continue; else { setbfile( buf, bname, "tickets" ); if((tick= fopen(buf, "w")) == NULL) break; fprintf(tick,"%s\n",inbuf); fclose(tick); break; } } move( t_lines - 2, 0); outs("開始投票了!"); } pressanykey(); return FULLUPDATE; } int vote_flag(bname, val) char *bname, val; { char buf[256], flag; int fd, num, size; num = usernum - 1; setbfile(buf, bname, STR_bv_flags); if ((fd = open(buf, O_RDWR | O_CREAT, 0600)) == -1) { return -1; } size = lseek(fd, 0, SEEK_END); memset(buf, 0, sizeof(buf)); while (size <= num) { write(fd, buf, sizeof(buf)); size += sizeof(buf); } lseek(fd, num, SEEK_SET); read(fd, &flag, 1); if (flag == 0 && val != 0) { lseek(fd, num, SEEK_SET); write(fd, &val, 1); } close(fd); return flag; } int same(compare, list, num) char compare; char list[]; int num; { int n; int rep = 0; for(n = 0; n < num; n++) { if(compare == list[n]) rep = 1; if(rep == 1) list[n] = list[n+1]; } return rep; } int user_vote(bname) char *bname; { FILE *cfp, *fcm; char buf[STRLEN]; char inbuf[80], choices[31], vote[2], bufvote[31]; int i = 0, tickets; int fd, count = 0; time_t closetime; setbfile( buf, bname, STR_bv_tickets); if((cfp= fopen(buf, "r")) == NULL) tickets=1; else { fgets( inbuf, sizeof(inbuf), cfp ); tickets = atoi(inbuf); fclose(cfp); } setbfile(buf, bname, STR_bv_control); move(3, 0); clrtobot(); if ((cfp = fopen(buf, "r")) == NULL) { /* woju boardheader bh; int bid = getbnum(bname); if (get_record(fn_board, &bh, sizeof(bh), bid) != -1 && bh.bvote == 1) { bh.bvote = 2; substitute_record(fn_board, &bh, sizeof(bh), bid); touch_boards(); resolve_boards(); } */ outs("\n目前並沒有任何投票舉行。"); pressanykey(); return FULLUPDATE; } if (!HAS_PERM(PERM_BASIC)) { outs("\n對不起! 您未滿二十歲, 還沒有投票權喔!"); fclose(cfp); pressanykey(); return FULLUPDATE; } setbfile(buf, bname, STR_bv_limited); /* Ptt */ if (dashf(buf)) { setbfile(buf, bname, FN_CANVOTE); if(!belong(buf, cuser.userid)) { outs("\n對不起! 這是私人投票..你並沒有受邀唷!"); fclose(cfp); pressanykey(); return FULLUPDATE; } else { outs("\n恭喜你受邀此次私人投票....<按任意鍵檢視此次受邀名單>"); pressanykey(); more(buf,YEA); } } setutmpmode(VOTING); setbfile(buf, bname, STR_bv_desc); more(buf, YEA); stand_title("投票箱"); fgets(inbuf, sizeof(inbuf), cfp); closetime = (time_t) atol(inbuf); prints("投票方式:確定好您的選擇後,輸入其代碼(A, B, C...)即可。\n" "此次投票你可以投 %1d 票。" " 按 0 取消投票 按 1 完成投票 \n" "此次投票將結束於:%s \n", tickets, ctime(&closetime)); move(5, 0); memset(choices, 0, sizeof(choices)); while (fgets(inbuf, sizeof(inbuf), cfp)) { choices[count++] = inbuf[0]; move(((count-1)%15)+5,((count-1)/15)*40); prints( " %s", strtok(inbuf,"\n\0")); } fclose(cfp); if (vote_flag(bname, '\0')) { move(21, 0); outs("此次投票,你已投過了!一人一次,大家平等。"); pressanykey(); return FULLUPDATE; } while(1) { vote[0] = vote[1] = '\0'; move(t_lines-2, 0); prints("你還可以投 %2d 票", tickets-i); getdata(t_lines-4, 0, "輸入您的選擇: ", vote, 3, DOECHO, 0); move(t_lines - 2, 0); *vote = toupper(*vote); if (vote[0] == '0' || (!vote[0] && !i)) { clrtoeol(); prints("記的再來投喔!! "); refresh(); break; } else if (vote[0] == '1' && i) ; else if (!vote[0]) continue; else if (index(choices, vote[0]) == NULL) /* 無效 */ continue; else if (same(vote[0], bufvote, i)) { move(((vote[0]-'A')%15)+5, (((vote[0]-'A'))/15)*40); prints(" "); i--; continue; } else { if (i == tickets) continue; bufvote[i] = vote[0]; move(((vote[0]-'A')%15)+5, (((vote[0]-'A'))/15)*40); prints("*"); i++; continue; } if (vote_flag(bname, vote[0]) != 0) prints("重覆投票! 不予計票。"); else { setbfile(buf, bname, STR_bv_ballots); if ((fd = open(buf, O_WRONLY | O_CREAT | O_APPEND, 0600)) == 0) outs("無法投入票匭\n"); else { struct stat statb; char buf[3], mycomments[3][74], b_comments[80]; for(i=0; i<3;i++) strcpy(mycomments[i],"\n"); flock(fd, LOCK_EX); write(fd, bufvote, i); flock(fd, LOCK_UN); fstat(fd, &statb); close(fd); move(0,0); clrtobot(); getdata(b_lines - 2, 0,"您對這次投票有什麼寶貴的意見嗎?(y/n)[N]", buf,3,DOECHO,0); if(buf[0]=='Y' || buf[0]=='y'){ move(5,0); outs("請問您對這次投票有什麼寶貴的意見?最多三行,按[Enter]結束"); for (i = 0; (i < 3) && getdata(7 + i, 0, ":", mycomments[i], 74, DOECHO, 0); i++); for(i = 0; i < 3; i++) strip_ansi(mycomments[i], mycomments[i] ,0); getdata(b_lines-2,0,"(S)儲存 (E)重新來過 (Q)取消?[S]",buf,3,LCECHO,0); setbfile(b_comments, bname, STR_bv_comments); if(mycomments[0]) if (fcm = fopen(b_comments, "a")){ fprintf(fcm, "○使用者 %s 的建議:\n", cuser.userid); for(i = 0; i < 3; i++) fprintf(fcm, " %s\n", mycomments[i]); fprintf(fcm, "\n"); fclose(fcm); } } move(b_lines -1 ,0); prints("已完成投票!(目前已投票數: %d)\n", statb.st_size); } } break; } pressanykey(); return FULLUPDATE; } int vote_results(bname) char *bname; { char buf[STRLEN]; setbfile(buf, bname, STR_bv_results); if (more(buf, YEA) == -1) { /* woju boardheader bh; int bid = getbnum(bname); if (get_record(fn_board, &bh, sizeof(bh), bid) != -1 && bh.bvote == 2) { bh.bvote = 0; substitute_record(fn_board, &bh, sizeof(bh), bid); touch_boards(); resolve_boards(); } */ move(3, 0); clrtobot(); outs("\n目前沒有任何投票的結果。"); pressanykey(); } /* woju else { boardheader bh; int bid = getbnum(bname); if (get_record(fn_board, &bh, sizeof(bh), bid) != -1 && bh.vtime < time(NULL) - 7 * 86400 && bh.bvote == 2) { bh.bvote = 0; substitute_record(fn_board, &bh, sizeof(bh), bid); touch_boards(); resolve_boards(); } } */ return FULLUPDATE; } int b_vote_maintain() { return vote_maintain(currboard); } int b_vote() { return user_vote(currboard); } int b_results() { return vote_results(currboard); } #ifdef SYS_VOTE int m_vote() { return vote_maintain(DEFAULT_BOARD); } int x_vote() { return user_vote(DEFAULT_BOARD); } int x_results() { return vote_results(DEFAULT_BOARD); } #endif /* SYS_VOTE */ #ifdef HAVE_REPORT b_report(s) char *s; { static int disable = NA; int fd; if (disable) return; if ((fd = open("trace.bvote", O_WRONLY, 0644)) != -1) { char buf[512]; char timestr[18], *thetime; time_t dtime; time(&dtime); thetime = ctime(&dtime); strncpy(timestr, &(thetime[4]), 15); timestr[15] = '\0'; flock(fd, LOCK_EX); lseek(fd, 0, L_XTND); sprintf(buf, "%s %-12s %-20s %s\n", timestr, cuser.userid, currboard, s); write(fd, buf, strlen(buf)); flock(fd, LOCK_UN); close(fd); return; } disable = YEA; return; } #endif /* HAVE_REPORT */