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 b4d31140 authored by rswindell's avatar rswindell

New JS bbs methods:

- bbs.show_msg()
- bbs.show_msg_header()
Re-worked the JS bbs.netmail() implementation
sbbs::show_msg(), show_msghdr(), msgtotxt() now take an smb_t* argument
(don't use the pseudo-global 'smb' in these functions any longer)
sbbs_t::putmsg() and JS console.putmsg() now accept an optional orig_columns
argument to specify the original column width of a text for intelligent
re-word-wrapping (e.g. as taken from a message header field). Previously, the
original-column value was hard-coded to 80 columns (technically, 79).
sbbs_t::show_msghdr() no longer sends a CRLF if the cursor is already at the
top-of-screen (TOS).
sbbs_t::show_msg() now uses the stored "columns" msg header fields to pass to
putmsg() to intelligently re-word-wrap message bodies for display.
sbbs_t::show_msg() and msgtotxt() return bool now instead of void.
JS MsgBase.get_all_msg_headers() now supports an optional "expand_fields"
argument (defaults to true). I contemplated just getting rid of the (few)
expanding header fields (more like default-value-header fields, like 'id'), but
decided against it, at least for now.
JS MsgBase.put_msg_header(), the "number_or_offset" argument is optional and
not needed if a header object argument is provided. Make this clear in this JS
docs for this method

Note:
I sat on this commit for a while because I noticed occasional errors like this:
    Node 1 <Digital Man> !ERROR 2 (No such file or directory) (WinError 0) in
    readmsgs.cpp line 217 (sbbs_t::loadposts) locking
    "path/to/sub" access=-100 info=smb_locksmbhdr msgbase not open
started cropping up after introducing these changes and which I never
root-caused. But after a clean-build and waiting a week, I haven't seen it
again, so hopefully it was just a incomplete rebuild issue and not a new bug.
parent 9759b8ae
......@@ -119,19 +119,24 @@ void sbbs_t::show_msgattr(smbmsg_t* msg)
/****************************************************************************/
/* Displays a message header to the screen */
/****************************************************************************/
void sbbs_t::show_msghdr(smbmsg_t* msg)
void sbbs_t::show_msghdr(smb_t* smb, smbmsg_t* msg)
{
char str[MAX_PATH+1];
char age[64];
char *sender=NULL;
int i;
smb_t saved_smb = this->smb;
attr(LIGHTGRAY);
if(useron.misc&CLRSCRN)
outchar(FF);
else
CRLF;
this->smb = *smb; // Needed for @-codes and JS bbs.smb_* properties
current_msg = msg; // Needed for @-codes and JS bbs.msg_* properties
attr(LIGHTGRAY);
if(!tos) {
if(useron.misc&CLRSCRN)
outchar(FF);
else
CRLF;
}
if(!menu("msghdr", P_NOERROR)) {
bprintf(text[MsgSubj],msg->subj);
if(msg->tags && *msg->tags)
......@@ -170,23 +175,24 @@ void sbbs_t::show_msghdr(smbmsg_t* msg)
bprintf(text[ForwardedFrom],sender
,timestr(*(time32_t *)msg->hfield_dat[i]));
}
this->smb = saved_smb;
}
/****************************************************************************/
/* Displays message header and text (if not deleted) */
/****************************************************************************/
void sbbs_t::show_msg(smbmsg_t* msg, long mode, post_t* post)
bool sbbs_t::show_msg(smb_t* smb, smbmsg_t* msg, long p_mode, post_t* post)
{
char* txt;
if((msg->hdr.type == SMB_MSG_TYPE_NORMAL && post != NULL && (post->upvotes || post->downvotes))
|| msg->hdr.type == SMB_MSG_TYPE_POLL)
msg->user_voted = smb_voted_already(&smb, msg->hdr.number
,cfg.sub[smb.subnum]->misc&SUB_NAME ? useron.name : useron.alias, NET_NONE, NULL);
msg->user_voted = smb_voted_already(smb, msg->hdr.number
,cfg.sub[smb->subnum]->misc&SUB_NAME ? useron.name : useron.alias, NET_NONE, NULL);
show_msghdr(msg);
show_msghdr(smb, msg);
if(msg->hdr.type == SMB_MSG_TYPE_POLL && post != NULL && smb.subnum < cfg.total_subs) {
if(msg->hdr.type == SMB_MSG_TYPE_POLL && post != NULL && smb->subnum < cfg.total_subs) {
char* answer;
int longest_answer = 0;
......@@ -222,8 +228,8 @@ void sbbs_t::show_msg(smbmsg_t* msg, long mode, post_t* post)
bool results_visible = false;
if((msg->hdr.auxattr&POLL_RESULTS_MASK) == POLL_RESULTS_OPEN)
results_visible = true;
else if((msg->from_net.type == NET_NONE && sub_op(smb.subnum))
|| smb_msg_is_from(msg, cfg.sub[smb.subnum]->misc&SUB_NAME ? useron.name : useron.alias, NET_NONE, NULL))
else if((msg->from_net.type == NET_NONE && sub_op(smb->subnum))
|| 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;
......@@ -244,44 +250,46 @@ void sbbs_t::show_msg(smbmsg_t* msg, long mode, post_t* post)
}
if(!msg->user_voted && !(useron.misc&EXPERT) && !(msg->hdr.auxattr&POLL_CLOSED) && !(useron.rest&FLAG('V')))
mnemonics(text[VoteInThisPollNow]);
return;
return true;
}
if((txt=smb_getmsgtxt(&smb, msg, 0)) != NULL) {
char* p = txt;
if(!(console&CON_RAW_IN)) {
mode|=P_WORDWRAP;
p = smb_getplaintext(msg, txt);
if(p == NULL)
p = txt;
else
bputs(text[MIMEDecodedPlainText]);
}
truncsp(p);
SKIP_CRLF(p);
putmsg(p, mode);
smb_freemsgtxt(txt);
if(column)
CRLF;
}
if((txt=smb_getmsgtxt(&smb,msg,GETMSGTXT_TAIL_ONLY))!=NULL) {
putmsg(txt, mode&(~P_WORDWRAP));
smb_freemsgtxt(txt);
if((txt=smb_getmsgtxt(smb, msg, 0)) == NULL)
return false;
char* p = txt;
if(!(console&CON_RAW_IN)) {
p_mode|=P_WORDWRAP;
p = smb_getplaintext(msg, txt);
if(p == NULL)
p = txt;
else
bputs(text[MIMEDecodedPlainText]);
}
truncsp(p);
SKIP_CRLF(p);
putmsg(p, p_mode, msg->columns);
smb_freemsgtxt(txt);
if(column)
CRLF;
if((txt=smb_getmsgtxt(smb,msg,GETMSGTXT_TAIL_ONLY))==NULL)
return false;
putmsg(txt, p_mode&(~P_WORDWRAP));
smb_freemsgtxt(txt);
return true;
}
/****************************************************************************/
/* Writes message header and text data to a text file */
/****************************************************************************/
void sbbs_t::msgtotxt(smbmsg_t* msg, char *str, bool header, ulong mode)
bool sbbs_t::msgtotxt(smb_t* smb, smbmsg_t* msg, const char *fname, bool header, ulong gettxt_mode)
{
char *buf;
char tmp[128];
int i;
FILE *out;
if((out=fnopen(&i,str,O_WRONLY|O_CREAT|O_APPEND))==NULL) {
errormsg(WHERE,ERR_OPEN,str,0);
return;
if((out=fnopen(&i,fname,O_WRONLY|O_CREAT|O_APPEND))==NULL) {
errormsg(WHERE,ERR_OPEN,fname,0);
return false;
}
if(header) {
fprintf(out,"\r\n");
......@@ -302,14 +310,17 @@ void sbbs_t::msgtotxt(smbmsg_t* msg, char *str, bool header, ulong mode)
fprintf(out,"\r\n\r\n");
}
buf=smb_getmsgtxt(&smb,msg,mode);
bool result = false;
buf=smb_getmsgtxt(smb, msg, gettxt_mode);
if(buf!=NULL) {
strip_invalid_attr(buf);
fputs(buf,out);
smb_freemsgtxt(buf);
result = true;
} else if(smb_getmsgdatlen(msg)>2)
errormsg(WHERE,ERR_READ,smb.file,smb_getmsgdatlen(msg));
errormsg(WHERE,ERR_READ,smb->file,smb_getmsgdatlen(msg));
fclose(out);
return result;
}
/****************************************************************************/
......
......@@ -2632,7 +2632,7 @@ js_email(JSContext *cx, uintN argc, jsval *arglist)
else if(JSVAL_IS_OBJECT(argv[i])) {
if((hdrobj = JSVAL_TO_OBJECT(argv[i])) == NULL)
return JS_FALSE;
if(!js_GetMsgHeaderObjectPrivates(cx, hdrobj, &resmb, &remsg)) {
if(!js_GetMsgHeaderObjectPrivates(cx, hdrobj, &resmb, &remsg, /* post: */NULL)) {
if(!js_ParseMsgHeaderObject(cx, hdrobj, &msg))
return JS_FALSE;
remsg = &msg;
......@@ -2668,13 +2668,11 @@ js_netmail(JSContext *cx, uintN argc, jsval *arglist)
{
jsval *argv=JS_ARGV(cx, arglist);
int32 mode=0;
const char *def="";
char* subj=(char *)def;
JSString* js_to;
JSString* js_subj=NULL;
char* to = NULL;
char* subj = NULL;
JSString* js_str;
JSObject* hdrobj;
sbbs_t* sbbs;
char* cstr;
smb_t* resmb = NULL;
smbmsg_t* remsg = NULL;
smbmsg_t msg;
......@@ -2689,20 +2687,23 @@ js_netmail(JSContext *cx, uintN argc, jsval *arglist)
if((sbbs=js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist)))==NULL)
return(JS_FALSE);
if((js_to=JS_ValueToString(cx, argv[0]))==NULL)
return(JS_FALSE);
for(uintN i=1;i<argc;i++) {
for(uintN i=0; i<argc; i++) {
if(JSVAL_IS_NUMBER(argv[i])) {
if(!JS_ValueToInt32(cx,argv[i],&mode))
return JS_FALSE;
}
else if(JSVAL_IS_STRING(argv[i]))
js_subj=JS_ValueToString(cx,argv[i]);
else if(JSVAL_IS_STRING(argv[i])) {
js_str = JS_ValueToString(cx, argv[i]);
if(to == NULL) {
JSSTRING_TO_MSTRING(cx, js_str, to, NULL);
} else if(subj == NULL) {
JSSTRING_TO_MSTRING(cx, js_str, subj, NULL);
}
}
else if(JSVAL_IS_OBJECT(argv[i])) {
if((hdrobj = JSVAL_TO_OBJECT(argv[i])) == NULL)
return JS_FALSE;
if(!js_GetMsgHeaderObjectPrivates(cx, hdrobj, &resmb, &remsg)) {
if(!js_GetMsgHeaderObjectPrivates(cx, hdrobj, &resmb, &remsg, /* post: */NULL)) {
if(!js_ParseMsgHeaderObject(cx, hdrobj, &msg))
return JS_FALSE;
remsg = &msg;
......@@ -2710,24 +2711,11 @@ js_netmail(JSContext *cx, uintN argc, jsval *arglist)
}
}
if(js_subj!=NULL) {
JSSTRING_TO_MSTRING(cx, js_subj, subj, NULL);
if(subj==NULL)
return JS_FALSE;
}
JSSTRING_TO_MSTRING(cx, js_to, cstr, NULL);
if(cstr==NULL) {
if(subj != def)
free(subj);
return JS_FALSE;
}
rc=JS_SUSPENDREQUEST(cx);
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->netmail(cstr, subj, mode, resmb, remsg)));
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->netmail(to, subj, mode, resmb, remsg)));
smb_freemsgmem(&msg);
if(subj != def)
free(subj);
free(cstr);
FREE_AND_NULL(subj);
FREE_AND_NULL(to);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
......@@ -3543,7 +3531,7 @@ js_post_msg(JSContext *cx, uintN argc, jsval *arglist)
else if(JSVAL_IS_OBJECT(argv[n])) {
if((hdrobj=JSVAL_TO_OBJECT(argv[n]))==NULL)
return JS_FALSE;
if(!js_GetMsgHeaderObjectPrivates(cx, hdrobj, &resmb, &remsg)) {
if(!js_GetMsgHeaderObjectPrivates(cx, hdrobj, &resmb, &remsg, /* post: */NULL)) {
if(!js_ParseMsgHeaderObject(cx, hdrobj, &msg))
return JS_FALSE;
remsg = &msg;
......@@ -3559,6 +3547,82 @@ js_post_msg(JSContext *cx, uintN argc, jsval *arglist)
return(JS_TRUE);
}
static JSBool
js_show_msg(JSContext *cx, uintN argc, jsval *arglist)
{
jsval *argv=JS_ARGV(cx, arglist);
int32 p_mode = 0;
uintN n;
JSObject* hdrobj;
sbbs_t* sbbs;
smb_t* smb = NULL;
smbmsg_t* msg = NULL;
post_t* post = NULL;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((sbbs=js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist)))==NULL)
return(JS_FALSE);
for(n=0; n<argc; n++) {
if(JSVAL_IS_NUMBER(argv[n])) {
if(!JS_ValueToInt32(cx, argv[n], &p_mode))
return JS_FALSE;
}
else if(JSVAL_IS_OBJECT(argv[n])) {
if((hdrobj=JSVAL_TO_OBJECT(argv[n]))==NULL)
return JS_FALSE;
if(!js_GetMsgHeaderObjectPrivates(cx, hdrobj, &smb, &msg, &post)) {
return JS_FALSE;
}
}
}
if(smb == NULL || msg == NULL)
return JS_TRUE;
rc=JS_SUSPENDREQUEST(cx);
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(sbbs->show_msg(smb, msg, p_mode, post)));
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_show_msg_header(JSContext *cx, uintN argc, jsval *arglist)
{
jsval *argv=JS_ARGV(cx, arglist);
uintN n;
JSObject* hdrobj;
sbbs_t* sbbs;
smb_t* smb = NULL;
smbmsg_t* msg = NULL;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if((sbbs=js_GetPrivate(cx, JS_THIS_OBJECT(cx, arglist)))==NULL)
return(JS_FALSE);
for(n=0; n<argc; n++) {
if(JSVAL_IS_OBJECT(argv[n])) {
if((hdrobj=JSVAL_TO_OBJECT(argv[n]))==NULL)
return JS_FALSE;
if(!js_GetMsgHeaderObjectPrivates(cx, hdrobj, &smb, &msg, NULL)) {
return JS_FALSE;
}
}
}
if(smb == NULL || msg == NULL)
return JS_TRUE;
rc=JS_SUSPENDREQUEST(cx);
sbbs->show_msghdr(smb, msg);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_msgscan_cfg(JSContext *cx, uintN argc, jsval *arglist)
{
......@@ -4138,11 +4202,21 @@ static jsSyncMethodSpec js_bbs_functions[] = {
},
{"post_msg", js_post_msg, 1, JSTYPE_BOOLEAN, JSDOCSTR("[sub-board=<i>current</i>] [,mode=<tt>WM_NONE</tt>] [,object reply_header]")
,JSDOCSTR("post a message in the specified message sub-board (number or internal code) "
"with optinal <i>mode</i> (bitfield)<br>"
"with optional <i>mode</i> (bitfield)<br>"
"If <i>reply_header</i> is specified (a header object returned from <i>MsgBase.get_msg_header()</i>), that header "
"will be used for the in-reply-to header fields.")
,313
},
{"show_msg", js_show_msg, 1, JSTYPE_BOOLEAN, JSDOCSTR("[object header] [,mode=<tt>P_NONE</tt>] ")
,JSDOCSTR("show a message's header and body (text) with optional print <i>mode</i> (bitfield)<br>"
"<i>header</i> must be a header object returned from <i>MsgBase.get_msg_header()</i>)")
,31702
},
{"show_msg_header", js_show_msg_header, 1, JSTYPE_VOID, JSDOCSTR("[object header]")
,JSDOCSTR("show a message's header (only)<br>"
"<i>header</i> must be a header object returned from <i>MsgBase.get_msg_header()</i>)")
,31702
},
{"cfg_msg_scan", js_msgscan_cfg, 0, JSTYPE_VOID, JSDOCSTR("[type=<tt>SCAN_CFG_NEW</tt>]")
,JSDOCSTR("configure message scan "
"(<i>type</i> is either <tt>SCAN_CFG_NEW</tt> or <tt>SCAN_CFG_TOYOU</tt>)")
......
......@@ -1156,6 +1156,7 @@ js_putmsg(JSContext *cx, uintN argc, jsval *arglist)
{
jsval *argv=JS_ARGV(cx, arglist);
int32 mode=0;
int32 columns=0;
JSString* str;
sbbs_t* sbbs;
char* cstr;
......@@ -1174,12 +1175,16 @@ js_putmsg(JSContext *cx, uintN argc, jsval *arglist)
if(!JS_ValueToInt32(cx,argv[1],&mode))
return JS_FALSE;
}
if(argc>2 && JSVAL_IS_NUMBER(argv[2])) {
if(!JS_ValueToInt32(cx,argv[2],&columns))
return JS_FALSE;
}
JSSTRING_TO_MSTRING(cx, str, cstr, NULL);
if(cstr==NULL)
return JS_FALSE;
rc=JS_SUSPENDREQUEST(cx);
sbbs->putmsg(cstr,mode);
sbbs->putmsg(cstr, mode, columns);
free(cstr);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
......@@ -1921,9 +1926,10 @@ static jsSyncMethodSpec js_console_functions[] = {
,JSDOCSTR("display one or more values as raw strings followed by a single carriage-return/line-feed pair (new-line)")
,315
},
{"putmsg", js_putmsg, 1, JSTYPE_VOID, JSDOCSTR("text [,mode=<tt>P_NONE</tt>]")
{"putmsg", js_putmsg, 1, JSTYPE_VOID, JSDOCSTR("text [,mode=<tt>P_NONE</tt>] [,orig_columns=0]")
,JSDOCSTR("display message text (Ctrl-A codes, @-codes, pipe codes, etc), "
"see <tt>P_*</tt> in <tt>sbbsdefs.js</tt> for <i>mode</i> bits")
"see <tt>P_*</tt> in <tt>sbbsdefs.js</tt> for <i>mode</i> bits.<br>"
"When <tt>P_WORDWRAP</tt> mode flag is specified, <i>orig_columns</i> specifies the original text column width, if known")
,310
},
{"center", js_center, 1, JSTYPE_VOID, JSDOCSTR("text")
......
......@@ -53,6 +53,7 @@ typedef struct
private_t *p;
BOOL expand_fields;
smbmsg_t msg;
post_t post;
} privatemsg_t;
......@@ -954,7 +955,7 @@ BOOL DLLCALL js_ParseMsgHeaderObject(JSContext* cx, JSObject* obj, smbmsg_t* msg
}
/* obj must've been previously returned from get_msg_header() */
BOOL DLLCALL js_GetMsgHeaderObjectPrivates(JSContext* cx, JSObject* obj, smb_t** smb, smbmsg_t** msg)
BOOL DLLCALL js_GetMsgHeaderObjectPrivates(JSContext* cx, JSObject* obj, smb_t** smb, smbmsg_t** msg, post_t** post)
{
privatemsg_t* p;
......@@ -968,6 +969,8 @@ BOOL DLLCALL js_GetMsgHeaderObjectPrivates(JSContext* cx, JSObject* obj, smb_t**
}
if(msg != NULL)
*msg = &p->msg;
if(post != NULL)
*post = &p->post;
return TRUE;
}
......@@ -1674,6 +1677,7 @@ js_get_all_msg_headers(JSContext *cx, uintN argc, jsval *arglist)
JSObject* retobj;
char numstr[16];
JSBool include_votes=JS_FALSE;
JSBool expand_fields=JS_TRUE;
post_t* post;
idxrec_t* idx;
......@@ -1706,8 +1710,15 @@ js_get_all_msg_headers(JSContext *cx, uintN argc, jsval *arglist)
return JS_FALSE;
}
if(argc && JSVAL_IS_BOOLEAN(argv[0]))
include_votes = JSVAL_TO_BOOLEAN(argv[0]);
uintN argn = 0;
if(argn < argc && JSVAL_IS_BOOLEAN(argv[argn])) {
include_votes = JSVAL_TO_BOOLEAN(argv[argn]);
argn++;
}
if(argn < argc && JSVAL_IS_BOOLEAN(argv[argn])) {
expand_fields = JSVAL_TO_BOOLEAN(argv[argn]);
argn++;
}
retobj = JS_NewObject(cx, NULL, NULL, obj);
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(retobj));
......@@ -1782,9 +1793,10 @@ js_get_all_msg_headers(JSContext *cx, uintN argc, jsval *arglist)
/* Parse boolean arguments first */
p->p=priv;
p->expand_fields=JS_TRUE; /* This parameter defaults to true */
p->expand_fields = expand_fields;
p->msg.idx = post[off].idx;
p->post = post[off];
rc=JS_SUSPENDREQUEST(cx);
priv->smb_result = smb_getmsghdr(&(priv->smb), &(p->msg));
......@@ -1848,8 +1860,8 @@ js_put_msg_header(JSContext *cx, uintN argc, jsval *arglist)
jsval *argv=JS_ARGV(cx, arglist);
uintN n;
JSBool by_offset=JS_FALSE;
JSBool msg_specified=JS_FALSE;
smbmsg_t msg;
smbmsg_t* modmsg = &msg;
JSObject* hdr=NULL;
private_t* p;
jsrefcount rc;
......@@ -1880,9 +1892,6 @@ js_put_msg_header(JSContext *cx, uintN argc, jsval *arglist)
if(!JS_ValueToInt32(cx,argv[n],(int32*)&msg.hdr.number))
return JS_FALSE;
}
msg_specified=JS_TRUE;
n++;
break;
} else if(JSVAL_IS_STRING(argv[n])) { /* Get by ID */
JSSTRING_TO_MSTRING(cx, JSVAL_TO_STRING(argv[n]), cstr, NULL);
HANDLE_PENDING(cx, cstr);
......@@ -1896,59 +1905,57 @@ js_put_msg_header(JSContext *cx, uintN argc, jsval *arglist)
}
free(cstr);
JS_RESUMEREQUEST(cx, rc);
msg_specified=JS_TRUE;
n++;
break;
}
else if(JSVAL_IS_OBJECT(argv[n])) {
hdr = JSVAL_TO_OBJECT(argv[n++]);
}
}
if(!msg_specified)
return JS_TRUE;
if(n==argc || !JSVAL_IS_OBJECT(argv[n])) /* no header supplied? */
if(hdr == NULL) /* no header supplied? */
return JS_TRUE;
hdr = JSVAL_TO_OBJECT(argv[n++]);
privatemsg_t* mp;
mp=(privatemsg_t*)JS_GetPrivate(cx,hdr);
if(mp != NULL && mp->expand_fields) {
JS_ReportError(cx, "Message header has 'expanded fields'", WHERE);
return JS_FALSE;
if(mp != NULL) {
if(mp->expand_fields) {
JS_ReportError(cx, "Message header has 'expanded fields'", WHERE);
return JS_FALSE;
}
modmsg = &mp->msg;
}
rc=JS_SUSPENDREQUEST(cx);
if((p->smb_result=smb_getmsgidx(&(p->smb), &msg))!=SMB_SUCCESS) {
if((p->smb_result=smb_getmsgidx(&(p->smb), modmsg))!=SMB_SUCCESS) {
JS_RESUMEREQUEST(cx, rc);
return JS_TRUE;
}
if((p->smb_result=smb_lockmsghdr(&(p->smb),&msg))!=SMB_SUCCESS) {
if((p->smb_result=smb_lockmsghdr(&(p->smb),modmsg))!=SMB_SUCCESS) {
JS_RESUMEREQUEST(cx, rc);
return JS_TRUE;
}
do {
if((p->smb_result=smb_getmsghdr(&(p->smb), &msg))!=SMB_SUCCESS)
if((p->smb_result=smb_getmsghdr(&(p->smb), modmsg))!=SMB_SUCCESS)
break;
smb_freemsghdrmem(&msg); /* prevent duplicate header fields */
smb_freemsghdrmem(modmsg); /* prevent duplicate header fields */
JS_RESUMEREQUEST(cx, rc);
if(!parse_header_object(cx, p, hdr, &msg, TRUE)) {
if(!parse_header_object(cx, p, hdr, modmsg, TRUE)) {
SAFECOPY(p->smb.last_error,"Header parsing failure (required field missing?)");
ret=JS_FALSE;
break;
}
rc=JS_SUSPENDREQUEST(cx);
if((p->smb_result=smb_putmsg(&(p->smb), &msg))!=SMB_SUCCESS)
if((p->smb_result=smb_putmsg(&(p->smb), modmsg))!=SMB_SUCCESS)
break;
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
} while(0);
smb_unlockmsghdr(&(p->smb),&msg);
smb_unlockmsghdr(&(p->smb),modmsg);
smb_freemsgmem(&msg);
JS_RESUMEREQUEST(cx, rc);
......@@ -2876,14 +2883,14 @@ static jsSyncMethodSpec js_msgbase_functions[] = {
"if you will be re-writing the header later with <i>put_msg_header()</i>")
,312
},
{"get_all_msg_headers", js_get_all_msg_headers, 1, JSTYPE_ARRAY, JSDOCSTR("[include_votes=<tt>false</tt>]")
{"get_all_msg_headers", js_get_all_msg_headers, 1, JSTYPE_ARRAY, JSDOCSTR("[include_votes=<tt>false</tt>] [,expand_fields=<tt>true</tt>]")
,JSDOCSTR("returns an object of all message headers indexed by message number.<br>"
"Message headers returned by this function include 2 additional properties: <tt>upvotes</tt> and <tt>downvotes</tt>.<br>"
"Vote messages are excluded by default.")
,316
},
{"put_msg_header", js_put_msg_header, 2, JSTYPE_BOOLEAN, JSDOCSTR("[by_offset=<tt>false</tt>,] number_or_offset, object header")
,JSDOCSTR("modify an existing message header")
{"put_msg_header", js_put_msg_header, 2, JSTYPE_BOOLEAN, JSDOCSTR("[by_offset=<tt>false</tt>,] [number_or_offset_or_id,] object header")
,JSDOCSTR("modify an existing message header (must have been 'got' without expanded fields)")
,310
},
{"get_msg_body", js_get_msg_body, 2, JSTYPE_STRING, JSDOCSTR("[by_offset=<tt>false</tt>,] number_or_offset_or_id_or_header [,strip_ctrl_a=<tt>false</tt>] "
......
......@@ -47,7 +47,7 @@
/* the attributes prior to displaying the message are always restored. */
/* Stops parsing/displaying upon CTRL-Z (only in P_CPM_EOF mode). */
/****************************************************************************/
char sbbs_t::putmsg(const char *buf, long mode)
char sbbs_t::putmsg(const char *buf, long mode, long org_cols)
{
char tmpatr,tmp2[256],tmp3[128];
char ret;
......@@ -77,7 +77,9 @@ char sbbs_t::putmsg(const char *buf, long mode)
*wrapoff = 0;
}
char *wrapped;
if((wrapped=::wordwrap((char*)str+l, cols-1, 79, /* handle_quotes: */TRUE)) == NULL)
if(org_cols < TERM_COLS_MIN)
org_cols = TERM_COLS_DEFAULT;
if((wrapped=::wordwrap((char*)str+l, cols - 1, org_cols - 1, /* handle_quotes: */TRUE)) == NULL)
errormsg(WHERE,ERR_ALLOC,"wordwrap buffer",0);
else {
truncsp_lines(wrapped);
......@@ -305,7 +307,7 @@ char sbbs_t::putmsg(const char *buf, long mode)
}
if(memcmp(str+l, "@WORDWRAP@", 10) == 0) {
l += 10;
putmsg(str+l, mode|P_WORDWRAP);
putmsg(str+l, mode|P_WORDWRAP, org_cols);
break;
}
......