/*-------------------------------------------------------*/
/* 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 */