Commit 74902cee authored by rswindell's avatar rswindell
Browse files

Message voting via QWKnet is now fully implemented:

- Users can be restricted from voting with the 'V' restriction
- Sub-boards can be disalbled for voting in SCFG
- VOTING.DAT can be include/excluded from QWK packets via user cfg
  (when a VOTING.DAT is received in a REP, the user cfg flag is auto-set)
- Adds several new text.dat lines (if not present in yours, uses the default)

What's not yet implemented:
- Notification of votes on your posted messages
- Method to view/audit all votes
- Polling
- Any special handling to auto-exclude votes from msg-related JavaScripts
parent cc8a5d9f
/* getmsg.cpp */
/* Synchronet message retrieval functions */
/* $Id$ */
......@@ -105,7 +103,7 @@ void sbbs_t::show_msgattr(ushort attr)
,attr&MSG_VALIDATED ? "Validated " :nulstr
,attr&MSG_REPLIED ? "Replied " :nulstr
,attr&MSG_NOREPLY ? "NoReply " :nulstr
,nulstr
,attr&MSG_POLL ? "Poll " :nulstr
,nulstr
,nulstr
,nulstr
......@@ -138,7 +136,6 @@ void sbbs_t::show_msghdr(smbmsg_t* msg)
bprintf(text[MsgSubj],msg->subj);
if(msg->hdr.attr)
show_msgattr(msg->hdr.attr);
bprintf(text[MsgTo],msg->to);
if(msg->to_net.addr!=NULL)
bprintf(text[MsgToNet],smb_netaddrstr(&msg->to_net,str));
......@@ -151,6 +148,8 @@ void sbbs_t::show_msghdr(smbmsg_t* msg)
if(msg->from_net.addr!=NULL && strchr(msg->from,'@')==NULL)
bprintf(text[MsgFromNet],smb_netaddrstr(&msg->from_net,str));
}
if(msg->upvotes || msg->downvotes)
bprintf(text[MsgVotes], msg->upvotes, msg->downvotes);
bprintf(text[MsgDate]
,timestr(msg->hdr.when_written.time)
,smb_zonestr(msg->hdr.when_written.zone,NULL)
......
/* msgtoqwk.cpp */
/* Synchronet message to QWK format conversion routine */
/* $Id$ */
......@@ -45,7 +43,7 @@
/* mode determines how to handle Ctrl-A codes */
/****************************************************************************/
ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, uint subnum
, int conf, FILE* hdrs)
, int conf, FILE* hdrs, FILE* voting)
{
char str[512],from[512],to[512],ch=0,tear=0,tearwatch=0,*buf,*p;
char asc;
......@@ -58,14 +56,40 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, uint subnum
smbmsg_t remsg;
time_t tt;
get_msgid(&cfg, subnum, msg, msgid, sizeof(msgid));
if(msg->hdr.attr&(MSG_VOTE|MSG_POLL)) {
if(voting == NULL)
return 0;
if(msg->hdr.attr&MSG_VOTE) {
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, "Vote = %hd\n", msg->hdr.vote);
else
fprintf(voting, "%sVote = true\n", msg->hdr.attr&MSG_UPVOTE ? "Up" : "Down");
} else {
fprintf(voting, "[poll:%s]\n", msgid);
}
if(msg->subj && *msg->subj)
fprintf(voting, "%s: %s\n",smb_hfieldtype(SUBJECT), msg->subj);
/* SENDER */
fprintf(voting, "%s: %s\n", smb_hfieldtype(SENDER), msg->from);
if(msg->from_net.type)
fprintf(voting, "%s: %s\n", smb_hfieldtype(SENDERNETADDR), smb_netaddrstr(&msg->from_net, tmp));
fprintf(voting, "Conference: %u\n", conf);
fputc('\n', voting);
return 0;
}
offset=(long)ftell(qwk_fp);
if(hdrs!=NULL) {
fprintf(hdrs,"[%lx]\n",offset);
/* Message-IDs */
fprintf(hdrs,"Message-ID: %s\n",get_msgid(&cfg,subnum,msg,msgid,sizeof(msgid)));
fprintf(hdrs,"%s: %s\n", smb_hfieldtype(RFC822MSGID), msgid);
if(msg->reply_id!=NULL)
fprintf(hdrs,"In-Reply-To: %s\n",msg->reply_id);
fprintf(hdrs,"%s: %s\n", smb_hfieldtype(RFC822REPLYID), msg->reply_id);
/* Time/Date/Zone info */
fprintf(hdrs,"WhenWritten: %-20s %04hx\n"
......@@ -224,7 +248,7 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, uint subnum
if(mode&QM_MSGID && (uint)subnum!=INVALID_SUB) {
size+=fprintf(qwk_fp,"@MSGID: %s%c"
,get_msgid(&cfg,subnum,msg,msgid,sizeof(msgid)),QWK_NEWLINE);
,msgid,QWK_NEWLINE);
if(msg->reply_id) {
SAFECOPY(tmp,msg->reply_id);
......
......@@ -63,6 +63,7 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
glob_t g;
FILE *stream,*qwk,*personal,*ndx;
FILE* hdrs=NULL;
FILE* voting=NULL;
DIR* dir;
DIRENT* dirent;
struct tm tm;
......@@ -294,6 +295,16 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
return(false);
}
}
if(useron.qwk&QWK_VOTING) {
SAFEPRINTF(str,"%sVOTING.DAT",cfg.temp_dir);
if((voting=fopen(str,"a"))==NULL) {
fclose(qwk);
if(hdrs!=NULL)
fclose(hdrs);
errormsg(WHERE,ERR_OPEN,str,0);
return(false);
}
}
l=(long)filelength(fileno(qwk));
if(l<1) {
fprintf(qwk,"%-128.128s","Produced by " VERSION_NOTICE " " COPYRIGHT_NOTICE);
......@@ -320,6 +331,8 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
fclose(qwk);
if(hdrs!=NULL)
fclose(hdrs);
if(voting!=NULL)
fclose(voting);
errormsg(WHERE,ERR_OPEN,str,0);
return(false);
}
......@@ -335,6 +348,8 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
fclose(qwk);
if(hdrs!=NULL)
fclose(hdrs);
if(voting!=NULL)
fclose(voting);
if(personal)
fclose(personal);
errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
......@@ -355,6 +370,8 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
fclose(qwk);
if(hdrs!=NULL)
fclose(hdrs);
if(voting!=NULL)
fclose(voting);
if(personal)
fclose(personal);
smb_close(&smb);
......@@ -393,7 +410,7 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
size=msgtoqwk(&msg,qwk,mode,INVALID_SUB,0,hdrs);
smb_unlockmsghdr(&smb,&msg);
smb_freemsgmem(&msg);
if(ndx) {
if(ndx && size) {
msgndx++;
f=ltomsbin(msgndx); /* Record number */
ch=0; /* Sub number, not used */
......@@ -457,6 +474,8 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
k|=LP_BYSELF;
if(useron.rest&FLAG('Q') || !(subscan[usrsub[i][j]].cfg&SUB_CFG_YSCAN))
k|=LP_OTHERS;
if(useron.qwk&QWK_VOTING)
k|=LP_POLLS|LP_VOTES;
post=loadposts(&posts,usrsub[i][j],subscan[usrsub[i][j]].ptr,k,NULL);
bprintf(text[NScanStatusFmt]
......@@ -478,6 +497,8 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
fclose(qwk);
if(hdrs!=NULL)
fclose(hdrs);
if(voting!=NULL)
fclose(voting);
if(personal)
fclose(personal);
smb_close(&smb);
......@@ -521,10 +542,10 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
else
mode&=~(QM_TAGLINE|QM_TO_QNET);
size=msgtoqwk(&msg,qwk,mode,usrsub[i][j],conf,hdrs);
size=msgtoqwk(&msg,qwk,mode,usrsub[i][j],conf,hdrs,voting);
smb_unlockmsghdr(&smb,&msg);
if(ndx) {
if(ndx && size) {
msgndx++;
f=ltomsbin(msgndx); /* Record number */
ch=0; /* Sub number, not used */
......@@ -540,8 +561,10 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
}
smb_freemsgmem(&msg);
(*msgcnt)++;
submsgs++;
if(size) {
(*msgcnt)++;
submsgs++;
}
if(cfg.max_qwkmsgs
&& !(useron.exempt&FLAG('O')) && (*msgcnt)>=cfg.max_qwkmsgs) {
bputs(text[QWKmsgLimitReached]);
......@@ -597,6 +620,8 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
fclose(qwk); /* close MESSAGE.DAT */
if(hdrs!=NULL)
fclose(hdrs); /* close HEADERS.DAT */
if(voting!=NULL)
fclose(voting);
if(personal) {
fclose(personal); /* close PERSONAL.NDX */
SAFEPRINTF(str,"%sPERSONAL.NDX",cfg.temp_dir);
......
/* pack_rep.cpp */
/* Synchronet QWK reply (REP) packet creation routine */
/* $Id$ */
......@@ -60,6 +58,7 @@ bool sbbs_t::pack_rep(uint hubnum)
mail_t* mail;
FILE* rep;
FILE* hdrs=NULL;
FILE* voting=NULL;
DIR* dir;
DIRENT* dirent;
smbmsg_t msg;
......@@ -100,6 +99,10 @@ bool sbbs_t::pack_rep(uint hubnum)
fexistcase(str);
if((hdrs=fopen(str,"a"))==NULL)
errormsg(WHERE,ERR_CREATE,str,0);
SAFEPRINTF(str,"%sVOTING.DAT",cfg.temp_dir);
fexistcase(str);
if((voting=fopen(str,"a"))==NULL)
errormsg(WHERE,ERR_CREATE,str,0);
/*********************/
/* Pack new messages */
......@@ -111,6 +114,8 @@ bool sbbs_t::pack_rep(uint hubnum)
fclose(rep);
if(hdrs!=NULL)
fclose(hdrs);
if(voting!=NULL)
fclose(voting);
errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
return(false);
}
......@@ -178,7 +183,7 @@ bool sbbs_t::pack_rep(uint hubnum)
continue;
}
post=loadposts(&posts,j,subscan[j].ptr,LP_BYSELF|LP_OTHERS|LP_PRIVATE|LP_REP,NULL);
post=loadposts(&posts,j,subscan[j].ptr,LP_BYSELF|LP_OTHERS|LP_PRIVATE|LP_REP|LP_VOTES|LP_POLLS,NULL);
eprintf(LOG_INFO,remove_ctrl_a(text[NScanStatusFmt],tmp)
,cfg.grp[cfg.sub[j]->grp]->sname
,cfg.sub[j]->lname,posts,msgs);
......@@ -217,7 +222,7 @@ bool sbbs_t::pack_rep(uint hubnum)
if(msg.from_net.type!=NET_QWK)
mode|=QM_TAGLINE;
msgtoqwk(&msg,rep,mode,j,cfg.qhub[hubnum]->conf[i],hdrs);
msgtoqwk(&msg,rep,mode,j,cfg.qhub[hubnum]->conf[i],hdrs,voting);
smb_freemsgmem(&msg);
smb_unlockmsghdr(&smb,&msg);
......@@ -234,6 +239,8 @@ bool sbbs_t::pack_rep(uint hubnum)
if(hdrs!=NULL)
fclose(hdrs);
if(voting!=NULL)
fclose(voting);
fclose(rep); /* close HUB_ID.MSG */
CRLF;
/* Look for extra files to send out */
......
/* qwk.cpp */
/* Synchronet QWK packet-related functions */
/* $Id$ */
......@@ -8,7 +6,7 @@
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2015 Rob Swindell - http://www.synchro.net/copyright.html *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
......@@ -378,7 +376,6 @@ void sbbs_t::qwk_success(ulong msgcnt, char bi, char prepack)
if(msgs)
free(mail);
}
}
/****************************************************************************/
......@@ -469,6 +466,8 @@ void sbbs_t::qwk_sec()
,useron.qwk&QWK_NOINDEX ? text[No]:text[Yes]);
bprintf(text[QWKSettingsControl]
,useron.qwk&QWK_NOCTRL ? text[No]:text[Yes]);
bprintf(text[QWKSettingsVoting]
,useron.qwk&QWK_VOTING ? text[Yes]:text[No]);
bprintf(text[QWKSettingsHeaders]
,useron.qwk&QWK_HEADERS ? text[Yes]:text[No]);
bprintf(text[QWKSettingsBySelf]
......@@ -482,7 +481,7 @@ void sbbs_t::qwk_sec()
bprintf(text[QWKSettingsExtended]
,useron.qwk&QWK_EXT ? text[Yes]:text[No]);
bputs(text[QWKSettingsWhich]);
ch=(char)getkeys("AEDFHIOQTYMNCXZV",0);
ch=(char)getkeys("AEDFHIOPQTYMNCXZV",0);
if(sys_status&SS_ABORT || !ch || ch=='Q' || !online)
break;
switch(ch) {
......@@ -537,6 +536,9 @@ void sbbs_t::qwk_sec()
useron.qwk^=QWK_TZ;
break;
case 'V':
useron.qwk^=QWK_VOTING;
break;
case 'P':
useron.qwk^=QWK_VIA;
break;
case 'M':
......@@ -1000,3 +1002,64 @@ int sbbs_t::set_qwk_flag(ulong flag)
return putuserrec(&cfg,useron.number,U_QWK,8,ultoa(useron.qwk,str,16));
}
bool sbbs_t::qwk_voting(const char* fname, smb_net_type_t net_type)
{
FILE *fp;
str_list_t ini;
str_list_t votes;
if((fp=fopen(fname,"r")) == NULL) {
errormsg(WHERE, ERR_OPEN, fname, 0);
return false;
}
ini = iniReadFile(fp);
fclose(fp);
if((votes = iniGetSectionList(ini, "vote:")) != NULL) {
smb_t smb;
unsigned u;
ZERO_VAR(smb);
smb.subnum = INVALID_SUB;
for(u = 0; votes[u] != NULL; u++) {
smbmsg_t msg;
ZERO_VAR(msg);
smb_hfield_str(&msg, RFC822MSGID, votes[u] + 5);
smb_hfield_str(&msg, RFC822REPLYID, iniGetString(ini, votes[u], smb_hfieldtype(RFC822REPLYID), NULL, NULL));
smb_hfield_str(&msg, SENDER, iniGetString(ini, votes[u], smb_hfieldtype(SENDER), NULL, NULL));
if(iniGetBool(ini, votes[u], "upvote", FALSE))
msg.hdr.attr = MSG_UPVOTE;
else if(iniGetBool(ini, votes[u], "downvote", FALSE))
msg.hdr.attr = MSG_DOWNVOTE;
else {
msg.hdr.attr = MSG_VOTE;
msg.hdr.vote = iniGetShortInt(ini, votes[u], "vote", 0);
}
if(net_type != NET_NONE)
smb_hfield_netaddr(&msg
,SENDERNETADDR, iniGetString(ini,votes[u], smb_hfieldtype(SENDERNETTYPE), NULL, NULL), &net_type);
uint subnum = resolve_qwkconf(iniGetInteger(ini, votes[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(&smb) != SMB_SUCCESS)
continue;
smb.subnum = subnum;
}
/* ToDo: prevent duplicate votes here */
smb_addvote(&smb, &msg, smb_storage_mode(&cfg, &smb));
}
if(smb.subnum != INVALID_SUB)
smb_close(&smb);
iniFreeStringList(votes);
}
iniFreeStringList(ini);
return true;
}
/* qwk.h */
/* Synchronet QWK-related structures, constants, and prototypes */
/* $Id$ */
......
/* readmsgs.cpp */
/* Synchronet public message reading function */
/* $Id$ */
......@@ -265,18 +263,27 @@ post_t * sbbs_t::loadposts(uint32_t *posts, uint subnum, ulong ptr, long mode, u
break;
}
if(idx.attr&(MSG_UPVOTE|MSG_DOWNVOTE)) {
if(idx.attr&MSG_VOTE) {
ulong u;
for(u = 0; u < l; u++)
if(post[u].idx.number == idx.msgnum)
if(post[u].idx.number == idx.remsg)
break;
if(u < l) {
if(idx.attr&MSG_UPVOTE)
switch(idx.attr&MSG_VOTE) {
case MSG_UPVOTE:
post[u].upvotes++;
else
break;
case MSG_DOWNVOTE:
post[u].downvotes++;
break;
}
}
continue;
if(!(mode&LP_VOTES))
continue;
}
if(idx.attr&MSG_POLL) {
if(!(mode&LP_POLLS))
continue;
}
if(idx.attr&MSG_PRIVATE && !(mode&LP_PRIVATE)
......@@ -1016,19 +1023,36 @@ int sbbs_t::scanposts(uint subnum, long mode, const char *find)
{
smbmsg_t vote;
if(cfg.sub[subnum]->misc&SUB_NOVOTING) {
bputs(text[VotingNotAllowed]);
domsg = false;
break;
}
if(smb_voted_already(&smb, msg.hdr.number
,cfg.sub[subnum]->misc&SUB_NAME ? useron.name : useron.alias, NET_NONE, NULL)) {
bputs(text[No]);
bputs(text[VotedAlready]);
domsg = false;
break;
}
if(useron.rest&FLAG('V')) {
bputs(text[R_Voting]);
domsg = false;
break;
}
mnemonics(text[VoteMsgUpDownOrQuit]);
long cmd = getkeys("UDQ", 0);
if(cmd != 'U' && cmd != 'D')
break;
ZERO_VAR(vote);
vote.hdr.attr = MSG_UPVOTE;
vote.hdr.attr = (cmd == 'U' ? MSG_UPVOTE : MSG_DOWNVOTE);
vote.hdr.thread_back = msg.hdr.number;
vote.hdr.when_written.time = msg.hdr.when_imported.time = time32(NULL);
vote.hdr.when_written.zone = msg.hdr.when_imported.zone = sys_timezone(&cfg);
smb_hfield_str(&vote, SENDER, cfg.sub[subnum]->misc&SUB_NAME ? useron.name : useron.alias);
vote.hdr.when_written.time = vote.hdr.when_imported.time = time32(NULL);
vote.hdr.when_written.zone = vote.hdr.when_imported.zone = sys_timezone(&cfg);
smb_hfield_str(&vote, SENDER, (cfg.sub[subnum]->misc&SUB_NAME) ? useron.name : useron.alias);
if(msg.id != NULL)
smb_hfield_str(&vote, RFC822REPLYID, msg.id);
sprintf(str, "%u", useron.number);
smb_hfield_str(&vote, SENDEREXT, str);
......
......@@ -891,6 +891,7 @@ public:
void qwksetptr(uint subnum, char *buf, int reset);
void qwkcfgline(char *buf,uint subnum);
int set_qwk_flag(ulong flag);
bool qwk_voting(const char* fname, smb_net_type_t);
/* pack_qwk.cpp */
bool pack_qwk(char *packet, ulong *msgcnt, bool prepack);
......@@ -906,7 +907,7 @@ public:
uint resolve_qwkconf(uint n);
/* msgtoqwk.cpp */
ulong msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, uint subnum, int conf, FILE* hdrs_dat);
ulong msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, uint subnum, int conf, FILE* hdrs_dat, FILE* voting_dat = NULL);
/* qwktomsg.cpp */
void qwk_new_msg(ulong confnum, smbmsg_t* msg, char* hdrblk, long offset, str_list_t headers, bool parse_sender_hfields);
......
......@@ -224,6 +224,7 @@ typedef struct js_callback {
/* (bits 8-15 default to off) */
/* Bit values for sub[x].misc */
#define SUB_NOVOTING (1L<<0) /* No voting allowed in this sub-board */
#define SUB_QNET (1L<<3) /* Sub-board is netted via QWK network */
#define SUB_PNET (1L<<4) /* Sub-board is netted via PostLink */
#define SUB_FIDO (1L<<5) /* Sub-board is netted via FidoNet */
......@@ -242,9 +243,9 @@ typedef struct js_callback {
#define SUB_NSDEF (1L<<18) /* New-Scan on by default */
#define SUB_INET (1L<<19) /* Sub-board is netted via Internet */
#define SUB_FAST (1L<<20) /* Fast storage mode */
#define SUB_KILL (1L<<21) /* Kill read messages automatically */
#define SUB_KILLP (1L<<22) /* Kill read pvt messages automatically */
#define SUB_SYSPERM (1L<<23) /* Sysop messages are permament */
#define SUB_KILL (1L<<21) /* Kill read messages automatically (NOT IMPLEMENTED) */
#define SUB_KILLP (1L<<22) /* Kill read pvt messages automatically (NOT IMPLEMENTED) */
#define SUB_SYSPERM (1L<<23) /* Sysop messages are permanent */
#define SUB_GATE (1L<<24) /* Gateway between Network types */
#define SUB_LZH (1L<<25) /* Use LZH compression for msgs */
#define SUB_SSDEF (1L<<26) /* Default ON for Scan for Your msgs */
......@@ -255,7 +256,7 @@ typedef struct js_callback {
#define SUB_HDRMOD (1L<<31) /* Modified sub-board header info (SCFG) */
/* Bit values for dir[x].misc */
#define DIR_FCHK (1<<0) /* Check for file existance */
#define DIR_FCHK (1<<0) /* Check for file existence */
#define DIR_RATE (1<<1) /* Force uploads to be rated G,R, or X */
#define DIR_MULT (1<<2) /* Ask for multi-disk numbering */
#define DIR_DUPES (1<<3) /* Search this dir for upload dupes */
......@@ -424,6 +425,7 @@ typedef enum { /* Values for xtrn_t.event */
#define QWK_EXT (1L<<13) /* QWK Extended (QWKE) format */
#define QWK_MSGID (1L<<14) /* Include "@MSGID" in msgs */
#define QWK_HEADERS (1L<<16) /* Include HEADERS.DAT file */
#define QWK_VOTING (1L<<17) /* Include POLLS.DAT and VOTES.DAT */
#define QWK_DEFAULT (QWK_FILES|QWK_ATTACH|QWK_EMAIL|QWK_DELMAIL)
......@@ -736,6 +738,8 @@ typedef enum { /* Values for xtrn_t.event */
#define LP_UNREAD (1<<2) /* Un-read messages only */
#define LP_PRIVATE (1<<3) /* Include all private messages */
#define LP_REP (1<<4) /* Packing REP packet */
#define LP_POLLS (1<<5) /* Include polls */
#define LP_VOTES (1<<6) /* Include votes */
/* Bits in the mode of loadmail() */
#define LM_UNREAD (1<<0) /* Include un-read mail only */
......
......@@ -822,6 +822,13 @@ enum {
,InTheFuture
,AgeOfPostedItem
,NodeStatusLogout
,VotingNotAllowed
,VotedAlready
,QWKSettingsVoting
,VoteMsgUpDownOrQuit
,MsgVotes
,MsgVoteNotice
,R_Voting
,TOTAL_TEXT
};
......
......@@ -11,7 +11,7 @@ const char * const text_defaults[TOTAL_TEXT]={
"\x01\x6e\x01\x63\xc4\xc4\xc4\xc4\xc4\xfa\xfa\xfa\xfa\x0d\x0a\x01\x68\xb3\x20\x01\x62\x53\x75\x62\x6a\x01\x6e\x01\x62\x3a\x20\x01"
"\x68\x01\x63\x25\x2e\x37\x30\x73\x0d\x0a"
,"\xb3\x20\x01\x62\x41\x74\x74\x72\x01\x6e\x01\x62\x3a\x20\x01\x68\x01\x63\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73"
"\x25\x73\x25\x73\x25\x73\x25\x73\x0d\x0a"
"\x25\x73\x25\x73\x25\x73\x25\x73\x25\x73\x0d\x0a"
,"\xb3\x20\x01\x62\x54\x6f\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x68\x01\x63\x25\x2e\x37\x30\x73"
,"\x20\x23\x25\x73"
,"\x20\x28\x25\x2e\x34\x30\x73\x29"
......@@ -767,8 +767,8 @@ const char * const text_defaults[TOTAL_TEXT]={
,"\x01\x5f\x01\x79\x01\x68\x41\x64\x6a\x75\x73\x74\x20\x4d\x69\x6e\x75\x74\x65\x73\x20\x28\x2d\x20\x74\x6f\x20\x73\x75\x62\x74\x72"
"\x61\x63\x74\x2c\x20\x48\x20\x3d\x20\x48\x6f\x75\x72\x73\x29\x3a\x20\x01\x6e"
,"\x0d\x0a\x44\x65\x6c\x65\x74\x65\x20\x51\x75\x65\x73\x74\x69\x6f\x6e\x61\x69\x72\x65"
,"\x01\x68\x01\x62\x55\x73\x65\x72\x20\x53\x65\x74\x74\x69\x6e\x67\x73\x20\x66\x6f\x72\x20\x01\x77\x25\x73\x20\x23\x25\x64\x0d\x0a"
"\x0d\x0a"
,"\x01\x68\x01\x62\x55\x73\x65\x72\x20\x53\x65\x74\x74\x69\x6e\x67\x73\x20\x66\x6f\x72\x20\x01\x77\x25\x73\x20\x23\x25\x64\x01\x62"
"\x3a\x0d\x0a\x0d\x0a"
,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x54\x01\x6e\x01\x62\x5d\x20\x01\x68\x54\x65\x72\x6d\x69\x6e\x61\x6c\x20\x4d\x6f\x64\x65\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a"
,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x45\x01\x6e\x01\x62\x5d\x20\x01\x68\x45\x78\x74\x65\x72\x6e\x61\x6c\x20\x45\x64\x69\x74\x6f"
......@@ -1195,8 +1195,8 @@ const char * const text_defaults[TOTAL_TEXT]={
,"\x20\x76\x69\x61\x20\x72\x6c\x6f\x67\x69\x6e"
,"\x20\x76\x69\x61\x20\x73\x73\x68"
,"\x20\x61\x74\x20\x25\x75\x62\x70\x73"
,"\x01\x68\x01\x62\x51\x57\x4b\x20\x53\x65\x74\x74\x69\x6e\x67\x73\x20\x66\x6f\x72\x20\x01\x77\x25\x73\x20\x23\x25\x75\x3a\x01\x6e"
"\x0d\x0a\x0d\x0a"
,"\x01\x68\x01\x62\x51\x57\x4b\x20\x53\x65\x74\x74\x69\x6e\x67\x73\x20\x66\x6f\x72\x20\x01\x77\x25\x73\x20\x23\x25\x75\x01\x62\x3a"
"\x01\x6e\x0d\x0a\x0d\x0a"
,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x41\x01\x6e\x01\x62\x5d\x20\x01\x68\x43\x74\x72\x6c\x2d\x41\x20\x43\x6f\x6c\x6f\x72\x20\x43"
"\x6f\x64\x65\x73\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a"
,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x54\x01\x6e\x01\x62\x5d\x20\x01\x68\x41\x72\x63\x68\x69\x76\x65\x20\x54\x79\x70\x65\x20\x20"
......@@ -1218,9 +1218,9 @@ const char * const text_defaults[TOTAL_TEXT]={
,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x59\x01\x6e\x01\x62\x5d\x20\x01\x68\x49\x6e\x63\x6c\x75\x64\x65\x20\x4d\x65\x73\x73\x61\x67"
"\x65\x73\x20\x66\x72\x6f\x6d\x20\x59\x6f\x75\x20\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a"
,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x5a\x01\x6e\x01\x62\x5d\x20\x01\x68\x49\x6e\x63\x6c\x75\x64\x65\x20\x54\x69\x6d\x65\x20\x5a"
"\x6f\x6e\x65\x20\x28\x54\x5a\x29\x20\x20\x20\x20\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a"
,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x56\x01\x6e\x01\x62\x5d\x20\x01\x68\x49\x6e\x63\x6c\x75\x64\x65\x20\x4d\x65\x73\x73\x61\x67"
"\x65\x20\x50\x61\x74\x68\x20\x28\x56\x49\x41\x29\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a"
"\x6f\x6e\x65\x20\x28\x40\x54\x5a\x29\x20\x20\x20\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a"
,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x50\x01\x6e\x01\x62\x5d\x20\x01\x68\x49\x6e\x63\x6c\x75\x64\x65\x20\x4d\x65\x73\x73\x61\x67"
"\x65\x20\x50\x61\x74\x68\x20\x28\x40\x56\x49\x41\x29\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a"
,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x4d\x01\x6e\x01\x62\x5d\x20\x01\x68\x49\x6e\x63\x6c\x75\x64\x65\x20\x4d\x65\x73\x73\x61\x67"
"\x65\x2f\x52\x65\x70\x6c\x79\x20\x49\x44\x73\x20\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a"
,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x58\x01\x6e\x01\x62\x5d\x20\x01\x68\x45\x78\x74\x65\x6e\x64\x65\x64\x20\x28\x51\x57\x4b\x45"
......@@ -1283,4 +1283,18 @@ const char * const text_defaults[TOTAL_TEXT]={
,"\x66\x72\x6f\x6d\x20\x6e\x6f\x77"
,"\x25\x73\x20\x25\x73\x20\x25\x73"
,"\x6c\x6f\x67\x67\x69\x6e\x67\x20\x6f\x75\x74\x20\x01\x68\x25\x73"
,"\x0d\x0a\x01\x68\x01\x72\x49\x27\x6d\x20\x73\x6f\x72\x72\x79\x2c\x20\x76\x6f\x74\x69\x6e\x67\x20\x69\x73\x20\x6e\x6f\x74\x20\x61"
"\x6c\x6c\x6f\x77\x65\x64\x20\x68\x65\x72\x65\x2e\x0d\x0a"
,"\x0d\x0a\x01\x68\x01\x72\x49\x27\x6d\x20\x73\x6f\x72\x72\x79\x2c\x20\x79\x6f\x75\x27\x76\x65\x20\x61\x6c\x72\x65\x61\x64\x79\x20"
"\x76\x6f\x74\x65\x64\x20\x6f\x6e\x20\x74\x68\x69\x73\x2e\x0d\x0a"
,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x56\x01\x6e\x01\x62\x5d\x20\x01\x68\x49\x6e\x63\x6c\x75\x64\x65\x20\x56\x4f\x54\x49\x4e\x47"
"\x2e\x44\x41\x54\x20\x46\x69\x6c\x65\x20\x20\x20\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a"
,"\x0d\x0a\x56\x6f\x74\x65\x20\x66\x6f\x72\x20\x6d\x65\x73\x73\x61\x67\x65\x3a\x20\x7e\x55\x70\x2c\x20\x7e\x44\x6f\x77\x6e\x2c\x20"
"\x6f\x72\x20\x7e\x51\x75\x69\x74\x3a\x20"
,"\x0d\x0a\xb3\x20\x01\x62\x4d\x73\x67\x20\x01\x6e\x01\x62\x3a\x20\x01\x68\x01\x63\x56\x6f\x74\x65\x64\x20\x55\x70\x20\x25\x75\x20"
"\x74\x69\x6d\x65\x73\x20\x61\x6e\x64\x20\x44\x6f\x77\x6e\x20\x25\x75\x20\x74\x69\x6d\x65\x73"
,"\x0d\x0a\x25\x73\x20\x25\x73\x2d\x76\x6f\x74\x65\x64\x20\x79\x6f\x75\x72\x20\x6d\x65\x73\x73\x61\x67\x65\x20\x6f\x6e\x20\x25\x73"
"\x0d\x0a"
,"\x0d\x0a\x01\x68\x01\x72\x49\x27\x6d\x20\x73\x6f\x72\x72\x79\x2c\x20\x79\x6f\x75\x27\x72\x65\x20\x6e\x6f\x74\x20\x61\x6c\x6c\x6f"
"\x77\x65\x64\x20\x74\x6f\x20\x76\x6f\x74\x65\x2e\x0d\x0a"
};
/* un_qwk.cpp */
/* Synchronet QWK unpacking routine */