Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

Commit 0ac4f937 authored by rswindell's avatar rswindell

Introduced 2 new poll concepts:

- Closures (polls can be closed for new voting by the pollster)
- Results can have configurable visibility:
  a. Only to voters (and the pollster) - the default
  b. Everyone
  c. Everyone once the poll has closed
  d. Only the pollster

Changes to smb_getmsgtxt():
Main change: poll questions can now be quoted when replying to a posted poll
(the results cannot be quoted).
Also: there's now automatically a blank line inserted between comment header
fields and poll answers or the msg body text.
Also: upon any malloc failure, the function now returns NULL.
New functions: smb_msg_is_from() and smb_addpollclosure().
parent 85c21d3f
......@@ -996,18 +996,23 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen)
if(!strcmp(sp,"MSG_TIMEZONE") && current_msg!=NULL)
return(smb_zonestr(current_msg->hdr.when_written.zone,NULL));
if(!strcmp(sp,"MSG_ATTR") && current_msg!=NULL) {
safe_snprintf(str,maxlen,"%s%s%s%s%s%s%s%s%s%s%s"
,current_msg->hdr.attr&MSG_PRIVATE ? "Private " :nulstr
,current_msg->hdr.attr&MSG_READ ? "Read " :nulstr
,current_msg->hdr.attr&MSG_DELETE ? "Deleted " :nulstr
,current_msg->hdr.attr&MSG_KILLREAD ? "Kill " :nulstr
,current_msg->hdr.attr&MSG_ANONYMOUS ? "Anonymous " :nulstr
,current_msg->hdr.attr&MSG_LOCKED ? "Locked " :nulstr
,current_msg->hdr.attr&MSG_PERMANENT ? "Permanent " :nulstr
,current_msg->hdr.attr&MSG_MODERATED ? "Moderated " :nulstr
,current_msg->hdr.attr&MSG_VALIDATED ? "Validated " :nulstr
,current_msg->hdr.attr&MSG_REPLIED ? "Replied " :nulstr
,current_msg->hdr.attr&MSG_NOREPLY ? "NoReply " :nulstr
uint16_t attr = current_msg->hdr.attr;
uint16_t poll = attr&MSG_POLL_VOTE_MASK;
uint32_t auxattr = current_msg->hdr.auxattr;
safe_snprintf(str,maxlen,"%s%s%s%s%s%s%s%s%s%s%s%s%s"
,attr&MSG_PRIVATE ? "Private " :nulstr
,attr&MSG_READ ? "Read " :nulstr
,attr&MSG_DELETE ? "Deleted " :nulstr
,attr&MSG_KILLREAD ? "Kill " :nulstr
,attr&MSG_ANONYMOUS ? "Anonymous " :nulstr
,attr&MSG_LOCKED ? "Locked " :nulstr
,attr&MSG_PERMANENT ? "Permanent " :nulstr
,attr&MSG_MODERATED ? "Moderated " :nulstr
,attr&MSG_VALIDATED ? "Validated " :nulstr
,attr&MSG_REPLIED ? "Replied " :nulstr
,attr&MSG_NOREPLY ? "NoReply " :nulstr
,poll == MSG_POLL ? "Poll " :nulstr
,poll == MSG_POLL && auxattr&POLL_CLOSED ? "(Closed) " :nulstr
);
return(str);
}
......
......@@ -88,8 +88,11 @@ int sbbs_t::loadmsg(smbmsg_t *msg, ulong number)
}
void sbbs_t::show_msgattr(ushort attr)
void sbbs_t::show_msgattr(smbmsg_t* msg)
{
uint16_t attr = msg->hdr.attr;
uint16_t poll = attr&MSG_POLL_VOTE_MASK;
uint32_t auxattr = msg->hdr.auxattr;
bprintf(text[MsgAttr]
,attr&MSG_PRIVATE ? "Private " :nulstr
......@@ -103,7 +106,8 @@ void sbbs_t::show_msgattr(ushort attr)
,attr&MSG_VALIDATED ? "Validated " :nulstr
,attr&MSG_REPLIED ? "Replied " :nulstr
,attr&MSG_NOREPLY ? "NoReply " :nulstr
,attr&MSG_POLL ? "Poll " :nulstr
,poll == MSG_POLL ? "Poll " :nulstr
,poll == MSG_POLL && auxattr&POLL_CLOSED ? "(Closed) " :nulstr
,nulstr
,nulstr
,nulstr
......@@ -135,7 +139,7 @@ void sbbs_t::show_msghdr(smbmsg_t* msg)
bprintf(text[MsgSubj],msg->subj);
if(msg->hdr.attr)
show_msgattr(msg->hdr.attr);
show_msgattr(msg);
if(msg->to && *msg->to) {
bprintf(text[MsgTo],msg->to);
if(msg->to_net.addr!=NULL)
......@@ -186,7 +190,7 @@ void sbbs_t::show_msg(smbmsg_t* msg, long mode, post_t* post)
show_msghdr(msg);
if(msg->hdr.type == SMB_MSG_TYPE_POLL && post != NULL) {
if(msg->hdr.type == SMB_MSG_TYPE_POLL && post != NULL && smb.subnum < cfg.total_subs) {
char* answer;
int longest_answer = 0;
uint16_t votes = smb_voted_already(&smb, msg->hdr.number
......@@ -222,7 +226,16 @@ void sbbs_t::show_msg(smbmsg_t* msg, long mode, post_t* post)
else if(width > cols-20)
width = cols-20;
bprintf(text[PollAnswerNumber], answers+1);
if(votes || sub_op(smb.subnum)) {
bool results_visible = false;
if((msg->hdr.auxattr&POLL_RESULTS_MASK) == POLL_RESULTS_OPEN)
results_visible = true;
else if(smb_msg_is_from(msg, cfg.sub[smb.subnum]->misc&SUB_NAME ? useron.name : useron.alias, NET_NONE, NULL))
results_visible = true;
else if((msg->hdr.auxattr&POLL_RESULTS_MASK) == POLL_RESULTS_CLOSED)
results_visible = (msg->hdr.auxattr&POLL_CLOSED) ? true : false;
else if((msg->hdr.auxattr&POLL_RESULTS_MASK) != POLL_RESULTS_SECRET)
results_visible = votes ? true : false;
if(results_visible) {
safe_snprintf(str, sizeof(str), text[PollAnswerFmt]
,width, width, answer, post->votes[answers], pct);
backfill(str, pct);
......@@ -235,6 +248,8 @@ void sbbs_t::show_msg(smbmsg_t* msg, long mode, post_t* post)
CRLF;
answers++;
}
if(!votes && !(useron.misc&EXPERT) && !(msg->hdr.auxattr&POLL_CLOSED) && !(useron.rest&FLAG('V')))
mnemonics("\r\nTo vote in this poll, hit ~V now.\r\n");
return;
}
if((txt=smb_getmsgtxt(&smb,msg,(console&CON_RAW_IN) ? 0:GETMSGTXT_PLAIN)) != NULL) {
......
......@@ -4425,7 +4425,7 @@ BOOL bounce(SOCKET sock, smb_t* smb, smbmsg_t* msg, char* err, BOOL immediate)
strcpy(str,"Reason:");
smb_hfield_str(&newmsg, SMB_COMMENT, str);
smb_hfield_str(&newmsg, SMB_COMMENT, err);
smb_hfield_str(&newmsg, SMB_COMMENT, "\r\nOriginal message text follows:\r\n");
smb_hfield_str(&newmsg, SMB_COMMENT, "\r\nOriginal message text follows:");
if((i=smb_addmsghdr(smb,&newmsg,SMB_SELFPACK))!=SMB_SUCCESS)
lprintf(LOG_ERR,"%04d !BOUNCE ERROR %d (%s) adding message header"
......
......@@ -58,32 +58,43 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, uint subnum
get_msgid(&cfg, subnum, msg, msgid, sizeof(msgid));
if(msg->hdr.type == SMB_MSG_TYPE_POLL || msg->hdr.type == SMB_MSG_TYPE_BALLOT) {
if(msg->hdr.type != SMB_MSG_TYPE_NORMAL) {
if(voting == NULL)
return 0;
if(msg->hdr.type == SMB_MSG_TYPE_BALLOT) {
switch(msg->hdr.type) {
case SMB_MSG_TYPE_BALLOT:
fprintf(voting, "[vote:%s]\n", msgid);
if((p = msg->reply_id) != NULL)
fprintf(voting, "%s: %s\n", smb_hfieldtype(RFC822REPLYID), p);
if((msg->hdr.attr&MSG_VOTE) == MSG_VOTE)
fprintf(voting, "Votes = 0x%hx\n", msg->hdr.votes);
else
fprintf(voting, "%sVote = true\n", msg->hdr.attr&MSG_UPVOTE ? "Up" : "Down");
} else {
break;
case SMB_MSG_TYPE_POLL:
{
unsigned comments = 0;
unsigned answers = 0;
fprintf(voting, "[poll:%s]\n", msgid);
if(msg->hdr.votes)
fprintf(voting, "MaxVotes = %hd\n", msg->hdr.votes);
unsigned comments = 0;
unsigned answers = 0;
if(msg->hdr.auxattr&POLL_RESULTS_MASK)
fprintf(voting , "Results = %u\n", (msg->hdr.auxattr&POLL_RESULTS_MASK) >> POLL_RESULTS_SHIFT);
for(i=0; i < msg->total_hfields; i++) {
if(msg->hfield[i].type == SMB_COMMENT)
fprintf(voting, "%s%u = %s\n", smb_hfieldtype(msg->hfield[i].type), comments++, (char*)msg->hfield_dat[i]);
else if(msg->hfield[i].type == SMB_POLL_ANSWER)
fprintf(voting, "%s%u = %s\n", smb_hfieldtype(msg->hfield[i].type), answers++, (char*)msg->hfield_dat[i]);
}
break;
}
case SMB_MSG_TYPE_POLL_CLOSURE:
fprintf(voting, "[close:%s]\n", msgid);
break;
}
if(msg->subj && *msg->subj)
fprintf(voting, "%s: %s\n",smb_hfieldtype(SUBJECT), msg->subj);
if(msg->reply_id)
fprintf(voting, "%s: %s\n", smb_hfieldtype(RFC822REPLYID), msg->reply_id);
/* SENDER */
fprintf(voting, "%s: %s\n", smb_hfieldtype(SENDER), msg->from);
if(msg->from_net.type)
......
......@@ -565,40 +565,60 @@ extern "C" int DLLCALL votemsg(scfg_t* cfg, smb_t* smb, smbmsg_t* msg, const cha
/* Look-up thread_back if RFC822 Reply-ID was specified */
if(msg->hdr.thread_back == 0 && msg->reply_id != NULL) {
if(smb_getmsgidx_by_msgid(smb, &remsg, msg->reply_id) == SMB_SUCCESS)
msg->hdr.thread_back = remsg.idx.number; /* needed for threading backward */
msg->hdr.thread_back = remsg.idx.number; /* poll or message being voted on */
}
if(smb_voted_already(smb, msg->hdr.thread_back, msg->from, (enum smb_net_type)msg->from_net.type, msg->from_net.addr))
return SMB_DUPE_MSG;
result = smb_addvote(smb, msg, smb_storage_mode(cfg, smb));
if(result == SMB_SUCCESS && smsgfmt != NULL) {
remsg.hdr.number = msg->hdr.thread_back;
if(smb_getmsgidx(smb, &remsg) == SMB_SUCCESS
&& smb_getmsghdr(smb, &remsg) == SMB_SUCCESS) {
if(remsg.from_ext != NULL) {
user_t user;
ZERO_VAR(user);
user.number = atoi(remsg.from_ext);
if(getuserdat(cfg, &user) == 0 &&
(stricmp(remsg.from, user.alias) == 0 || stricmp(remsg.from, user.name) == 0)) {
char from[256];
char tstr[128];
char smsg[256];
if(msg->from_net.type)
safe_snprintf(from, sizeof(from), "%s (%s)", msg->from, smb_netaddr(&msg->from_net));
else
SAFECOPY(from, msg->from);
safe_snprintf(smsg, sizeof(smsg), smsgfmt
,timestr(cfg, msg->hdr.when_written.time, tstr)
,cfg->grp[cfg->sub[smb->subnum]->grp]->sname
,cfg->sub[smb->subnum]->sname
,from
,remsg.subj);
putsmsg(cfg, user.number, smsg);
}
}
smb_freemsgmem(&remsg);
remsg.hdr.number = msg->hdr.thread_back;
if((result = smb_getmsgidx(smb, &remsg)) != SMB_SUCCESS)
return result;
if((result = smb_getmsghdr(smb, &remsg)) != SMB_SUCCESS)
return result;
if(remsg.hdr.auxattr&POLL_CLOSED)
result = SMB_CLOSED;
else
result = smb_addvote(smb, msg, smb_storage_mode(cfg, smb));
if(result == SMB_SUCCESS && smsgfmt != NULL && remsg.from_ext != NULL) {
user_t user;
ZERO_VAR(user);
user.number = atoi(remsg.from_ext);
if(getuserdat(cfg, &user) == 0 &&
(stricmp(remsg.from, user.alias) == 0 || stricmp(remsg.from, user.name) == 0)) {
char from[256];
char tstr[128];
char smsg[256];
if(msg->from_net.type)
safe_snprintf(from, sizeof(from), "%s (%s)", msg->from, smb_netaddr(&msg->from_net));
else
SAFECOPY(from, msg->from);
safe_snprintf(smsg, sizeof(smsg), smsgfmt
,timestr(cfg, msg->hdr.when_written.time, tstr)
,cfg->grp[cfg->sub[smb->subnum]->grp]->sname
,cfg->sub[smb->subnum]->sname
,from
,remsg.subj);
putsmsg(cfg, user.number, smsg);
}
}
smb_freemsgmem(&remsg);
return result;
}
extern "C" int DLLCALL closepoll(scfg_t* cfg, smb_t* smb, uint32_t msgnum, const char* username)
{
int result;
smbmsg_t msg;
ZERO_VAR(msg);
msg.hdr.when_imported.time = time32(NULL);
msg.hdr.when_imported.zone = sys_timezone(cfg);
msg.hdr.when_written = msg.hdr.when_imported;
msg.hdr.thread_back = msgnum;
smb_hfield_str(&msg, SENDER, username);
result = smb_addpollclosure(smb, &msg, smb_storage_mode(cfg, smb));
smb_freemsgmem(&msg);
return result;
}
\ No newline at end of file
}
......@@ -1002,12 +1002,57 @@ int sbbs_t::set_qwk_flag(ulong flag)
return putuserrec(&cfg,useron.number,U_QWK,8,ultoa(useron.qwk,str,16));
}
static void parse_common_header_fields(str_list_t ini, const char* section, smbmsg_t* msg, smb_net_type_t net_type, const char* qnet_id)
{
char* p;
char zone[32];
if((p=iniGetString(ini, section, "WhenWritten", NULL, NULL)) != NULL) {
xpDateTime_t dt=isoDateTimeStr_parse(p);
msg->hdr.when_written.time=(uint32_t)xpDateTime_to_localtime(dt);
msg->hdr.when_written.zone=dt.zone;
sscanf(p,"%*s %s",zone);
if(zone[0])
msg->hdr.when_written.zone=(ushort)strtoul(zone,NULL,16);
}
if((p=iniGetString(ini, section, smb_hfieldtype(SENDER), NULL, NULL)) != NULL)
smb_hfield_str(msg, SENDER, p);
if(net_type == NET_QWK) {
char fulladdr[256];
const char* netaddr = iniGetString(ini, section, smb_hfieldtype(SENDERNETADDR), NULL, NULL);
if(netaddr == NULL)
netaddr = qnet_id;
else {
SAFEPRINTF2(fulladdr, "%s/%s", qnet_id, netaddr);
netaddr = fulladdr;
}
if(netaddr != NULL) {
smb_hfield_netaddr(msg, SENDERNETADDR, netaddr, &net_type);
smb_hfield(msg, SENDERNETTYPE, sizeof(net_type), &net_type);
}
}
if((p=iniGetString(ini, section, smb_hfieldtype(RFC822REPLYID), NULL, NULL)) != NULL)
smb_hfield_str(msg, RFC822REPLYID, p);
/* Trace header fields */
while((p=iniGetString(ini, section, smb_hfieldtype(SENDERIPADDR), NULL, NULL)) != NULL)
smb_hfield_str(msg, SENDERIPADDR, p);
while((p=iniGetString(ini, section, smb_hfieldtype(SENDERHOSTNAME), NULL, NULL)) != NULL)
smb_hfield_str(msg, SENDERHOSTNAME, p);
while((p=iniGetString(ini, section, smb_hfieldtype(SENDERPROTOCOL), NULL, NULL)) != NULL)
smb_hfield_str(msg, SENDERPROTOCOL, p);
while((p=iniGetString(ini,section, smb_hfieldtype(SENDERORG), NULL, NULL)) != NULL)
smb_hfield_str(msg, SENDERORG, p);
}
bool sbbs_t::qwk_voting(const char* fname, smb_net_type_t net_type, const char* qnet_id)
{
FILE *fp;
str_list_t ini;
str_list_t poll_list;
str_list_t ballot_list;
str_list_t list;
if((fp=fopen(fname,"r")) == NULL) {
errormsg(WHERE, ERR_OPEN, fname, 0);
......@@ -1016,31 +1061,32 @@ bool sbbs_t::qwk_voting(const char* fname, smb_net_type_t net_type, const char*
ini = iniReadFile(fp);
fclose(fp);
if((poll_list = iniGetSectionList(ini, "poll:")) != NULL) {
if((list = iniGetSectionList(ini, "poll:")) != NULL) {
smb_t smb;
unsigned u;
ZERO_VAR(smb);
smb.subnum = INVALID_SUB;
for(u = 0; poll_list[u] != NULL; u++) {
for(u = 0; list[u] != NULL; u++) {
uint subnum = resolve_qwkconf(iniGetInteger(ini, list[u], "Conference", 0));
if(subnum == INVALID_SUB)
continue;
if(cfg.sub[subnum]->misc&SUB_NOVOTING)
continue;
smbmsg_t msg;
ZERO_VAR(msg);
smb_hfield_str(&msg, RFC822MSGID, poll_list[u] + 5);
smb_hfield_str(&msg, SENDER, iniGetString(ini, poll_list[u], smb_hfieldtype(SENDER), NULL, NULL));
msg.hdr.votes = iniGetShortInt(ini, poll_list[u], "votes", 0);
if(net_type != NET_NONE) {
const char* netaddr = iniGetString(ini, poll_list[u], smb_hfieldtype(SENDERNETADDR), NULL, NULL);
if(netaddr == NULL)
netaddr = qnet_id;
smb_hfield_netaddr(&msg, SENDERNETADDR, netaddr, &net_type);
smb_hfield(&msg, SENDERNETTYPE, sizeof(net_type), &net_type);
}
smb_hfield_str(&msg, RFC822MSGID, list[u] + 5);
parse_common_header_fields(ini, list[u], &msg, net_type, qnet_id);
msg.hdr.votes = iniGetShortInt(ini, list[u], "votes", 0);
ulong results = iniGetLongInt(ini, list[u], "results", 0);
msg.hdr.auxattr = (results << POLL_RESULTS_SHIFT) & POLL_RESULTS_MASK;
for(int i=0;;i++) {
char str[128];
SAFEPRINTF2(str, "%s%u", smb_hfieldtype(SMB_COMMENT), i);
const char* comment = iniGetString(ini, poll_list[u], str, NULL, NULL);
const char* comment = iniGetString(ini, list[u], str, NULL, NULL);
if(comment == NULL)
break;
smb_hfield_str(&msg, SMB_COMMENT, comment);
......@@ -1048,89 +1094,115 @@ bool sbbs_t::qwk_voting(const char* fname, smb_net_type_t net_type, const char*
for(int i=0;;i++) {
char str[128];
SAFEPRINTF2(str, "%s%u", smb_hfieldtype(SMB_POLL_ANSWER), i);
const char* answer = iniGetString(ini, poll_list[u], str, NULL, NULL);
const char* answer = iniGetString(ini, list[u], str, NULL, NULL);
if(answer == NULL)
break;
smb_hfield_str(&msg, SMB_POLL_ANSWER, answer);
}
uint subnum = resolve_qwkconf(iniGetInteger(ini, poll_list[u], "Conference", 0));
if(subnum == INVALID_SUB)
continue;
if(cfg.sub[subnum]->misc&SUB_NOVOTING)
continue;
if(subnum != smb.subnum) {
if(smb.subnum != INVALID_SUB) {
smb_close(&smb);
smb.subnum = INVALID_SUB;
}
if(smb_open_sub(&cfg, &smb, subnum) != SMB_SUCCESS)
continue;
smb_open_sub(&cfg, &smb, subnum);
}
int i;
if((i=smb_addpoll(&smb, &msg, smb_storage_mode(&cfg, &smb))) != SMB_SUCCESS)
errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
smb_freemsgmem(&msg);
}
if(smb.subnum != INVALID_SUB)
smb_close(&smb);
iniFreeStringList(poll_list);
iniFreeStringList(list);
}
if((ballot_list = iniGetSectionList(ini, "vote:")) != NULL) {
if((list = iniGetSectionList(ini, "vote:")) != NULL) {
smb_t smb;
unsigned u;
ZERO_VAR(smb);
smb.subnum = INVALID_SUB;
for(u = 0; ballot_list[u] != NULL; u++) {
for(u = 0; list[u] != NULL; u++) {
uint subnum = resolve_qwkconf(iniGetInteger(ini, list[u], "Conference", 0));
if(subnum == INVALID_SUB)
continue;
if(cfg.sub[subnum]->misc&SUB_NOVOTING)
continue;
smbmsg_t msg;
const char* notice = NULL;
ZERO_VAR(msg);
smb_hfield_str(&msg, RFC822MSGID, ballot_list[u] + 5);
smb_hfield_str(&msg, RFC822REPLYID, iniGetString(ini, ballot_list[u], smb_hfieldtype(RFC822REPLYID), NULL, NULL));
smb_hfield_str(&msg, SENDER, iniGetString(ini, ballot_list[u], smb_hfieldtype(SENDER), NULL, NULL));
if(iniGetBool(ini, ballot_list[u], "upvote", FALSE)) {
smb_hfield_str(&msg, RFC822MSGID, list[u] + 5);
parse_common_header_fields(ini, list[u], &msg, net_type, qnet_id);
if(iniGetBool(ini, list[u], "upvote", FALSE)) {
msg.hdr.attr = MSG_UPVOTE;
notice = text[MsgUpVoteNotice];
}
else if(iniGetBool(ini, ballot_list[u], "downvote", FALSE)) {
else if(iniGetBool(ini, list[u], "downvote", FALSE)) {
msg.hdr.attr = MSG_DOWNVOTE;
notice = text[MsgDownVoteNotice];
}
else {
msg.hdr.attr = MSG_VOTE;
msg.hdr.votes = iniGetShortInt(ini, ballot_list[u], "votes", 0);
msg.hdr.votes = iniGetShortInt(ini, list[u], "votes", 0);
notice = text[PollVoteNotice];
}
if(net_type != NET_NONE) {
const char* netaddr = iniGetString(ini,ballot_list[u], smb_hfieldtype(SENDERNETADDR), NULL, NULL);
if(netaddr == NULL)
netaddr = qnet_id;
smb_hfield_netaddr(&msg, SENDERNETADDR, netaddr, &net_type);
smb_hfield(&msg, SENDERNETTYPE, sizeof(net_type), &net_type);
if(subnum != smb.subnum) {
if(smb.subnum != INVALID_SUB) {
smb_close(&smb);
smb.subnum = INVALID_SUB;
}
smb_open_sub(&cfg, &smb, subnum);
}
uint subnum = resolve_qwkconf(iniGetInteger(ini, ballot_list[u], "Conference", 0));
int i;
if((i=votemsg(&cfg, &smb, &msg, notice)) != SMB_SUCCESS)
errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
smb_freemsgmem(&msg);
}
if(smb.subnum != INVALID_SUB)
smb_close(&smb);
iniFreeStringList(list);
}
if((list = iniGetSectionList(ini, "close:")) != NULL) {
smb_t smb;
unsigned u;
ZERO_VAR(smb);
smb.subnum = INVALID_SUB;
for(u = 0; list[u] != NULL; u++) {
uint subnum = resolve_qwkconf(iniGetInteger(ini, list[u], "Conference", 0));
if(subnum == INVALID_SUB)
continue;
if(cfg.sub[subnum]->misc&SUB_NOVOTING)
continue;
smbmsg_t msg;
const char* notice = NULL;
ZERO_VAR(msg);
smb_hfield_str(&msg, RFC822MSGID, list[u] + 6);
parse_common_header_fields(ini, list[u], &msg, net_type, qnet_id);
if(subnum != smb.subnum) {
if(smb.subnum != INVALID_SUB) {
smb_close(&smb);
smb.subnum = INVALID_SUB;
}
if(smb_open_sub(&cfg, &smb, subnum) != SMB_SUCCESS)
continue;
smb_open_sub(&cfg, &smb, subnum);
}
int i;
if((i=votemsg(&cfg, &smb, &msg, notice)) != SMB_SUCCESS)
if((i=smb_addpollclosure(&smb, &msg, smb_storage_mode(&cfg, &smb))) != SMB_SUCCESS)
errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
smb_freemsgmem(&msg);
}
if(smb.subnum != INVALID_SUB)
smb_close(&smb);
iniFreeStringList(ballot_list);
iniFreeStringList(list);
}
iniFreeStringList(ini);
return true;
}
......@@ -110,9 +110,9 @@ static void qwk_parse_header_list(ulong confnum, smbmsg_t* msg, str_list_t* head
if(parse_sender_hfields)
smb_hfield_str(msg,hfield_type,p);
}
while((p=iniPopKey(headers,ROOT_SECTION,"Organization",value))!=NULL) {
while((p=iniPopKey(headers,ROOT_SECTION,smb_hfieldtype(hfield_type=SENDERORG),value))!=NULL) {
if(parse_sender_hfields)
smb_hfield_str(msg,SENDERORG,p);
smb_hfield_str(msg,hfield_type,p);
}
/* FidoNet header fields */
......
......@@ -575,7 +575,7 @@ void sbbs_t::readmail(uint usernumber, int which)
done=1;
break;
case 'C': /* Change attributes of last piece */
i=chmsgattr(msg.hdr.attr);
i=chmsgattr(msg);
if(msg.hdr.attr==i)
break;
if(msg.total_hfields)
......
......@@ -40,7 +40,7 @@ int sbbs_t::sub_op(uint subnum)
return(is_user_subop(&cfg, subnum, &useron, &client));
}
char sbbs_t::msg_listing_flag(uint subnum, smbmsg_t* msg, post_t* post)
uchar sbbs_t::msg_listing_flag(uint subnum, smbmsg_t* msg, post_t* post)
{
if(msg->hdr.attr&MSG_DELETE) return '-';
if((stricmp(msg->to,useron.alias)==0 || stricmp(msg->to,useron.name)==0)
......@@ -52,7 +52,7 @@ char sbbs_t::msg_listing_flag(uint subnum, smbmsg_t* msg, post_t* post)
if(msg->hdr.number > subscan[subnum].ptr) return '*';
if(msg->hdr.attr&MSG_PRIVATE) return 'P';
if(msg->hdr.attr&MSG_POLL) return '?';
if(post->upvotes > post->downvotes) return 'V';
if(post->upvotes > post->downvotes) return 251;
if(post->upvotes || post->downvotes) return 'v';
if(msg->hdr.attr&MSG_REPLIED) return 'R';
if(sub_op(subnum) && msg->hdr.attr&MSG_ANONYMOUS) return 'A';
......@@ -266,8 +266,12 @@ post_t * sbbs_t::loadposts(uint32_t *posts, uint subnum, ulong ptr, long mode, u
if(mode&LP_REP || !sub_op(subnum))
break;
}
if(idx.attr&MSG_VOTE) {
switch(idx.attr&MSG_POLL_VOTE_MASK) {
case MSG_VOTE:
case MSG_UPVOTE:
case MSG_DOWNVOTE:
{
ulong u;
for(u = 0; u < l; u++)
if(post[u].idx.number == idx.remsg)
......@@ -289,10 +293,16 @@ post_t * sbbs_t::loadposts(uint32_t *posts, uint subnum, ulong ptr, long mode, u
}
if(!(mode&LP_VOTES))
continue;
break;
}
if(idx.attr&MSG_POLL) {
case MSG_POLL:
if(!(mode&LP_POLLS))
continue;
break;
case MSG_POLL_CLOSURE:
if(!(mode&LP_VOTES))
continue;
break;
}
if(idx.attr&MSG_PRIVATE && !(mode&LP_PRIVATE)
......@@ -824,6 +834,18 @@ int sbbs_t::scanposts(uint subnum, long mode, const char *find)
else done=1;
break;
</