Newer
Older
if(smb_lockmsghdr(smb,msg)!=0)
return(NULL);
if(smb_getmsghdr(smb, msg)!=0) {
smb_unlockmsghdr(smb, msg);
return(NULL);
}
if((buf=smb_getmsgtxt(smb, msg, mode))==NULL) {
smb_unlockmsghdr(smb,msg);
return(NULL);
}
smb_unlockmsghdr(smb, msg);
if(strip_ctrl_a) {
char* newbuf;
if((newbuf=malloc(strlen(buf)+1))!=NULL) {
int i,j;
for(i=j=0;buf[i];i++) {
if(buf[i]==CTRL_A && buf[i+1]!=0)
i++;
else newbuf[j++]=buf[i];
}
newbuf[j]=0;
strcpy(buf,newbuf);
free(newbuf);
}
}
if(rfc822) { /* must escape lines starting with dot ('.') */
char* newbuf;
if((newbuf=malloc((strlen(buf)*2)+1))!=NULL) {
int i,j;
for(i=j=0;buf[i];i++) {
if((i==0 || buf[i-1]=='\n') && buf[i]=='.')
newbuf[j++]='.';
newbuf[j++]=buf[i];
}
newbuf[j]=0;
free(buf);
buf = newbuf;
}
}
return(buf);
}
static JSBool
js_get_msg_body(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
char* buf;
uintN n;
JSBool by_offset=JS_FALSE;
JSBool strip_ctrl_a=JS_FALSE;
JSBool tails=JS_TRUE;
JSBool rfc822=JS_FALSE;
JSBool msg_specified=JS_FALSE;
private_t* p;
*rval = JSVAL_NULL;
if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
JS_ReportError(cx,getprivate_failure,WHERE);
return(JS_FALSE);
if(!SMB_IS_OPEN(&(p->smb)))
return(JS_TRUE);
memset(&msg,0,sizeof(msg));
for(n=0;n<argc;n++) {
if(JSVAL_IS_BOOLEAN(argv[n]))
by_offset=JSVAL_TO_BOOLEAN(argv[n]);
else if(JSVAL_IS_NUMBER(argv[n])) {
if(by_offset) /* Get by offset */
JS_ValueToInt32(cx,argv[n],(int32*)&msg.offset);
else /* Get by number */
JS_ValueToInt32(cx,argv[n],(int32*)&msg.hdr.number);
msg_specified=JS_TRUE;
n++;
break;
} else if(JSVAL_IS_STRING(argv[n])) { /* Get by ID */
if(!msg_offset_by_id(scfg,&(p->smb)
,JS_GetStringBytes(JSVAL_TO_STRING(argv[n]))
,&msg.offset))
return(JS_TRUE); /* ID not found */
msg_specified=JS_TRUE;
n++;
break;
}
}
if(!msg_specified) /* No message number or id specified */
return(JS_TRUE);
if(n<argc && JSVAL_IS_BOOLEAN(argv[n]))
strip_ctrl_a=JSVAL_TO_BOOLEAN(argv[n++]);
if(n<argc && JSVAL_IS_BOOLEAN(argv[n]))
rfc822=JSVAL_TO_BOOLEAN(argv[n++]);
if(n<argc && JSVAL_IS_BOOLEAN(argv[n]))
tails=JSVAL_TO_BOOLEAN(argv[n++]);
buf = get_msg_text(&(p->smb), &msg, strip_ctrl_a, rfc822, tails ? GETMSGTXT_TAILS : 0);
if(buf==NULL)
return(JS_TRUE);
if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)
*rval = STRING_TO_JSVAL(js_str);
smb_freemsgtxt(buf);
return(JS_TRUE);
}
static JSBool
js_get_msg_tail(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
char* buf;
uintN n;
smbmsg_t msg;
JSBool by_offset=JS_FALSE;
JSBool strip_ctrl_a=JS_FALSE;
JSBool rfc822=JS_FALSE;
JSBool msg_specified=JS_FALSE;
private_t* p;
*rval = JSVAL_NULL;
if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
JS_ReportError(cx,getprivate_failure,WHERE);
return(JS_FALSE);
if(!SMB_IS_OPEN(&(p->smb)))
return(JS_TRUE);
memset(&msg,0,sizeof(msg));
for(n=0;n<argc;n++) {
if(JSVAL_IS_BOOLEAN(argv[n]))
by_offset=JSVAL_TO_BOOLEAN(argv[n]);
else if(JSVAL_IS_NUMBER(argv[n])) {
if(by_offset) /* Get by offset */
JS_ValueToInt32(cx,argv[n],(int32*)&msg.offset);
else /* Get by number */
JS_ValueToInt32(cx,argv[n],(int32*)&msg.hdr.number);
msg_specified=JS_TRUE;
n++;
break;
} else if(JSVAL_IS_STRING(argv[n])) { /* Get by ID */
if(!msg_offset_by_id(scfg,&(p->smb)
,JS_GetStringBytes(JSVAL_TO_STRING(argv[n]))
,&msg.offset))
return(JS_TRUE); /* ID not found */
msg_specified=JS_TRUE;
n++;
break;
}
}
if(!msg_specified) /* No message number or id specified */
return(JS_TRUE);
if(n<argc && JSVAL_IS_BOOLEAN(argv[n]))
strip_ctrl_a=JSVAL_TO_BOOLEAN(argv[n++]);
if(n<argc && JSVAL_IS_BOOLEAN(argv[n]))
rfc822=JSVAL_TO_BOOLEAN(argv[n++]);
buf = get_msg_text(&(p->smb), &msg, strip_ctrl_a, rfc822, GETMSGTXT_TAILS|GETMSGTXT_NO_BODY);
if(buf==NULL)
return(JS_TRUE);
if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)
*rval = STRING_TO_JSVAL(js_str);
smb_freemsgtxt(buf);
return(JS_TRUE);
}
static JSBool
js_save_msg(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
char* body=NULL;
uintN n;
JSObject* hdr=NULL;
jsval open_rval;
private_t* p;
*rval = BOOLEAN_TO_JSVAL(JS_FALSE);
if(argc<2)
return(JS_TRUE);
if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
JS_ReportError(cx,getprivate_failure,WHERE);
if(!SMB_IS_OPEN(&(p->smb))) {
if(!js_open(cx, obj, 0, NULL, &open_rval))
return(JS_FALSE);
if(open_rval == JSVAL_FALSE)
return(JS_TRUE);
}
for(n=0;n<argc;n++) {
if(JSVAL_IS_OBJECT(argv[n]))
hdr = JSVAL_TO_OBJECT(argv[n]);
else if(JSVAL_IS_STRING(argv[n])) {
if((body=JS_GetStringBytes(JSVAL_TO_STRING(argv[n])))==NULL) {
JS_ReportError(cx,"JS_GetStringBytes failed");
return(JS_FALSE);
}
}
}
if(hdr==NULL || body==NULL)
if(!parse_header_object(cx, p, hdr, &msg))
if(msg.hdr.when_written.time==0) {
msg.hdr.when_written.time=time(NULL);
msg.hdr.when_written.zone=sys_timezone(scfg);
truncsp(body);
if(savemsg(scfg, &(p->smb), &msg, body)==0)
*rval = BOOLEAN_TO_JSVAL(JS_TRUE);
return(JS_TRUE);
}
/* MsgBase Object Properites */
enum {
SMB_PROP_LAST_ERROR
,SMB_PROP_FILE
,SMB_PROP_DEBUG
,SMB_PROP_RETRY_TIME
,SMB_PROP_RETRY_DELAY
,SMB_PROP_LAST_MSG // last message number
,SMB_PROP_TOTAL_MSGS // total messages
,SMB_PROP_MAX_CRCS // Maximum number of CRCs to keep in history
,SMB_PROP_MAX_MSGS // Maximum number of message to keep in sub
,SMB_PROP_MAX_AGE // Maximum age of message to keep in sub (in days)
,SMB_PROP_ATTR // Attributes for this message base (SMB_HYPER,etc)
,SMB_PROP_IS_OPEN
};
static JSBool js_msgbase_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
jsint tiny;
private_t* p;
if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
JS_ReportError(cx,getprivate_failure,WHERE);
return(JS_FALSE);
tiny = JSVAL_TO_INT(id);
switch(tiny) {
case SMB_PROP_RETRY_TIME:
p->smb.retry_time = JSVAL_TO_INT(*vp);
break;
case SMB_PROP_RETRY_DELAY:
p->smb.retry_delay = JSVAL_TO_INT(*vp);
break;
case SMB_PROP_DEBUG:
p->debug = JSVAL_TO_BOOLEAN(*vp);
break;
}
return(JS_TRUE);
}
static JSBool js_msgbase_get(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
char* s=NULL;
JSString* js_str;
private_t* p;
if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
JS_ReportError(cx,getprivate_failure,WHERE);
return(JS_FALSE);
tiny = JSVAL_TO_INT(id);
switch(tiny) {
case SMB_PROP_FILE:
break;
case SMB_PROP_LAST_ERROR:
break;
case SMB_PROP_RETRY_TIME:
*vp = INT_TO_JSVAL(p->smb.retry_time);
break;
case SMB_PROP_RETRY_DELAY:
*vp = INT_TO_JSVAL(p->smb.retry_delay);
break;
case SMB_PROP_DEBUG:
*vp = INT_TO_JSVAL(p->debug);
break;
case SMB_PROP_FIRST_MSG:
memset(&idx,0,sizeof(idx));
smb_getfirstidx(&(p->smb),&idx);
JS_NewNumberValue(cx,idx.number,vp);
case SMB_PROP_LAST_MSG:
smb_getstatus(&(p->smb));
JS_NewNumberValue(cx,p->smb.status.last_msg,vp);
break;
case SMB_PROP_TOTAL_MSGS:
smb_getstatus(&(p->smb));
JS_NewNumberValue(cx,p->smb.status.total_msgs,vp);
break;
case SMB_PROP_MAX_CRCS:
JS_NewNumberValue(cx,p->smb.status.max_crcs,vp);
break;
case SMB_PROP_MAX_MSGS:
JS_NewNumberValue(cx,p->smb.status.max_msgs,vp);
break;
case SMB_PROP_MAX_AGE:
JS_NewNumberValue(cx,p->smb.status.max_age,vp);
break;
case SMB_PROP_ATTR:
JS_NewNumberValue(cx,p->smb.status.attr,vp);
case SMB_PROP_SUBNUM:
*vp = INT_TO_JSVAL(p->smb.subnum);
break;
case SMB_PROP_IS_OPEN:
*vp = BOOLEAN_TO_JSVAL(SMB_IS_OPEN(&(p->smb)));
break;
if(s!=NULL) {
if((js_str=JS_NewStringCopyZ(cx, s))==NULL)
return(JS_FALSE);
*vp = STRING_TO_JSVAL(js_str);
}
return(JS_TRUE);
}
#define SMB_PROP_FLAGS JSPROP_ENUMERATE|JSPROP_READONLY
static jsSyncPropertySpec js_msgbase_properties[] = {
/* name ,tinyid ,flags, ver */
{ "error" ,SMB_PROP_LAST_ERROR ,SMB_PROP_FLAGS, 310 },
{ "last_error" ,SMB_PROP_LAST_ERROR ,JSPROP_READONLY, 311 }, /* alias */
{ "file" ,SMB_PROP_FILE ,SMB_PROP_FLAGS, 310 },
{ "debug" ,SMB_PROP_DEBUG ,0, 310 },
{ "retry_time" ,SMB_PROP_RETRY_TIME ,JSPROP_ENUMERATE, 310 },
{ "retry_delay" ,SMB_PROP_RETRY_DELAY ,JSPROP_ENUMERATE, 311 },
{ "first_msg" ,SMB_PROP_FIRST_MSG ,SMB_PROP_FLAGS, 310 },
{ "last_msg" ,SMB_PROP_LAST_MSG ,SMB_PROP_FLAGS, 310 },
{ "total_msgs" ,SMB_PROP_TOTAL_MSGS ,SMB_PROP_FLAGS, 310 },
{ "max_crcs" ,SMB_PROP_MAX_CRCS ,SMB_PROP_FLAGS, 310 },
{ "max_msgs" ,SMB_PROP_MAX_MSGS ,SMB_PROP_FLAGS, 310 },
{ "max_age" ,SMB_PROP_MAX_AGE ,SMB_PROP_FLAGS, 310 },
{ "attributes" ,SMB_PROP_ATTR ,SMB_PROP_FLAGS, 310 },
{ "subnum" ,SMB_PROP_SUBNUM ,SMB_PROP_FLAGS, 310 },
{ "is_open" ,SMB_PROP_IS_OPEN ,SMB_PROP_FLAGS, 310 },
#ifdef _DEBUG
static char* msgbase_prop_desc[] = {
"last occurred message base error - <small>READ ONLY</small>"
,"base path and filename of message base - <small>READ ONLY</small>"
,"message base open/lock retry timeout (in seconds)"
,"delay between message base open/lock retries (in milliseconds)"
,"first message number - <small>READ ONLY</small>"
,"last message number - <small>READ ONLY</small>"
,"total number of messages - <small>READ ONLY</small>"
,"maximum number of message CRCs to store (for dupe checking) - <small>READ ONLY</small>"
,"maximum number of messages before expiration - <small>READ ONLY</small>"
,"maximum age (in days) of messages to store - <small>READ ONLY</small>"
,"message base attributes - <small>READ ONLY</small>"
,"sub-board number (0-based, -1 for e-mail) - <small>READ ONLY</small>"
,"<i>true</i> if the message base has been opened successfully - <small>READ ONLY</small>"
,NULL
};
#endif
static JSClass js_msgbase_class = {
"MsgBase" /* name */
,JSCLASS_HAS_PRIVATE /* flags */
,JS_PropertyStub /* addProperty */
,JS_PropertyStub /* delProperty */
,js_msgbase_get /* getProperty */
,js_msgbase_set /* setProperty */
,JS_EnumerateStub /* enumerate */
,JS_ResolveStub /* resolve */
,JS_ConvertStub /* convert */
,js_finalize_msgbase /* finalize */
};
static jsSyncMethodSpec js_msgbase_functions[] = {
{"open", js_open, 0, JSTYPE_BOOLEAN, JSDOCSTR("")
,JSDOCSTR("open message base")
,310
},
{"close", js_close, 0, JSTYPE_BOOLEAN, JSDOCSTR("")
,JSDOCSTR("close message base (if open)")
,310
{"get_msg_header", js_get_msg_header, 2, JSTYPE_OBJECT, JSDOCSTR("[boolean by_offset,] number_or_id")
,JSDOCSTR("returns a specific message header, <i>null</i> on failure")
,310
{"put_msg_header", js_put_msg_header, 2, JSTYPE_BOOLEAN, JSDOCSTR("[boolean by_offset,] number, object header")
,JSDOCSTR("write a message header")
,310
{"get_msg_body", js_get_msg_body, 2, JSTYPE_STRING, JSDOCSTR("[boolean by_offset,] number_or_id [,boolean strip_ctrl_a]")
,JSDOCSTR("returns the body text of a specific message, <i>null</i> on failure")
,310
{"get_msg_tail", js_get_msg_tail, 2, JSTYPE_STRING, JSDOCSTR("[boolean by_offset,] number_or_id [,boolean strip_ctrl_a]")
,JSDOCSTR("returns the tail text of a specific message, <i>null</i> on failure")
,310
{"get_msg_index", js_get_msg_index, 2, JSTYPE_OBJECT, JSDOCSTR("[boolean by_offset,] number")
,JSDOCSTR("returns a specific message index, <i>null</i> on failure. "
"The index object will contain the following properties:<br>"
"<table>"
"<tr><td><tt>subject</tt><td>CRC-16 of lowercase message subject"
"<tr><td><tt>to</tt><td>CRC-16 of lowercase recipient's name (or user number if e-mail)"
"<tr><td><tt>from</tt><td>CRC-16 of lowercase sender's name (or user number if e-mail)"
"<tr><td><tt>attr</tt><td>Attribute bitfield"
"<tr><td><tt>time</tt><td>Date/time (in time_t format)"
"<tr><td><tt>number</tt><td>Message number"
"<tr><td><tt>offset</tt><td>Byte-offset into header file"
"</table>")
,311
},
{"remove_msg", js_remove_msg, 2, JSTYPE_BOOLEAN, JSDOCSTR("[boolean by_offset,] number_or_id")
,JSDOCSTR("mark message as deleted")
,311
{"save_msg", js_save_msg, 2, JSTYPE_BOOLEAN, JSDOCSTR("object header, string body_text")
,JSDOCSTR("create a new message in message base, the <i>header</i> object may contain the following properties:<br>"
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
"<table>"
"<tr><td><tt>subject</tt><td>Message subject <i>(required)</i>"
"<tr><td><tt>to</tt><td>Recipient's name <i>(required)</i>"
"<tr><td><tt>to_ext</tt><td>Recipient's user number (for local e-mail)"
"<tr><td><tt>to_org</tt><td>Recipient's organization"
"<tr><td><tt>to_net_type</tt><td>Recipient's network type (default: 0 for local)"
"<tr><td><tt>to_net_addr</tt><td>Recipient's network address"
"<tr><td><tt>to_agent</tt><td>Recipient's agent type"
"<tr><td><tt>from</tt><td>Sender's name <i>(required)</i>"
"<tr><td><tt>from_ext</tt><td>Sender's user number"
"<tr><td><tt>from_org</tt><td>Sender's organization"
"<tr><td><tt>from_net_type</tt><td>Sender's network type (default: 0 for local)"
"<tr><td><tt>from_net_addr</tt><td>Sender's network address"
"<tr><td><tt>replyto</tt><td>Replies should be sent to this name"
"<tr><td><tt>replyto_ext</tt><td>Replies should be sent to this user number"
"<tr><td><tt>replyto_org</tt><td>Replies should be sent to organization"
"<tr><td><tt>replyto_net_type</tt><td>Replies should be sent to this network type"
"<tr><td><tt>replyto_net_addr</tt><td>Replies should be sent to this network address"
"<tr><td><tt>replyto_agent</tt><td>Replies should be sent to this agent type"
"<tr><td><tt>id</tt><td>Message's RFC-822 compliant Message-ID"
"<tr><td><tt>reply_id</tt><td>Message's RFC-822 compliant Reply-ID"
"<tr><td><tt>reverse_path</tt><td>Message's SMTP sender address"
"<tr><td><tt>path</tt><td>Messages's NNTP path"
"<tr><td><tt>newsgroups</tt><td>Message's NNTP newsgroups header"
"<tr><td><tt>ftn_msgid</tt><td>FidoNet FTS-9 Message-ID"
"<tr><td><tt>ftn_reply</tt><td>FidoNet FTS-9 Reply-ID"
"<tr><td><tt>ftn_area</tt><td>FidoNet FTS-4 echomail AREA tag"
"<tr><td><tt>ftn_flags</tt><td>FidoNet FSC-53 FLAGS"
"<tr><td><tt>ftn_pid</tt><td>FidoNet FSC-46 Program Identifier"
"<tr><td><tt>ftn_tid</tt><td>FidoNet FSC-46 Tosser Identifier"
"<tr><td><tt>date</tt><td>RFC-822 formatted date/time"
"<tr><td><tt>attr</tt><td>Attribute bitfield"
"<tr><td><tt>auxattr</tt><td>Auxillary attribute bitfield"
"<tr><td><tt>netattr</tt><td>Network attribute bitfield"
"<tr><td><tt>when_written_time</tt><td>Date/time (in time_t format)"
"<tr><td><tt>when_written_zone</tt><td>Time zone"
"<tr><td><tt>when_imported_time</tt><td>Date/time message was imported"
"<tr><td><tt>when_imported_zone</tt><td>Time zone"
"<tr><td><tt>thread_orig</tt><td>Replying to this message number"
"<tr><td><tt>thread_next</tt><td>Number of next message in this thread"
"<tr><td><tt>thread_first</tt><td>Number of first reply to this message"
"<tr><td><tt>field_list[].type</tt><td>Other SMB header fields (type)"
"<tr><td><tt>field_list[].data</tt><td>Other SMB header fields (data)"
"</table>")
,310
},
/* MsgBase Constructor (open message base) */
static JSBool
js_msgbase_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
JSString* js_str;
JSObject* cfgobj;
char* base;
private_t* p;
if((p=(private_t*)malloc(sizeof(private_t)))==NULL) {
JS_ReportError(cx,"malloc failed");
return(JS_FALSE);
}
memset(p,0,sizeof(private_t));
p->smb.retry_time=scfg->smb_retry_time;
js_str = JS_ValueToString(cx, argv[0]);
base=JS_GetStringBytes(js_str);
p->debug=JS_FALSE;
if(!JS_SetPrivate(cx, obj, p)) {
JS_ReportError(cx,"JS_SetPrivate failed");
free(p);
return(JS_FALSE);
}
if(!js_DefineSyncProperties(cx,obj,js_msgbase_properties)) {
free(p);
return(JS_FALSE);
}
#ifdef _DEBUG
js_DescribeSyncObject(cx,obj,"Class used for accessing message bases",310);
js_DescribeSyncConstructor(cx,obj,"To create a new MsgBase object: "
"<tt>var msgbase = new MsgBase('<i>code</i>')</tt><br>"
"where <i>code</i> is a sub-board internal code, or <tt>mail</tt> for the e-mail message base");
js_CreateArrayOfStrings(cx, obj, "_property_desc_list", msgbase_prop_desc, JSPROP_READONLY);
#endif
if(stricmp(base,"mail")==0) {
p->smb.subnum=INVALID_SUB;
snprintf(p->smb.file,sizeof(p->smb.file),"%s%s",scfg->data_dir,"mail");
} else {
for(p->smb.subnum=0;p->smb.subnum<scfg->total_subs;p->smb.subnum++) {
if(!stricmp(scfg->sub[p->smb.subnum]->code,base)) /* null ptr dereference here Apr-16-2003 */
break;
}
if(p->smb.subnum<scfg->total_subs) {
cfgobj=JS_NewObject(cx,NULL,NULL,obj);
js_CreateMsgAreaProperties(cx, scfg, cfgobj, p->smb.subnum);
#ifdef _DEBUG
js_DescribeSyncObject(cx,cfgobj
,"Configuration parameters for this message area (<i>sub-boards only</i>) "
"- <small>READ ONLY</small>"
,310);
#endif
JS_DefineProperty(cx,obj,"cfg",OBJECT_TO_JSVAL(cfgobj)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
snprintf(p->smb.file,sizeof(p->smb.file),"%s%s"
,scfg->sub[p->smb.subnum]->data_dir,scfg->sub[p->smb.subnum]->code);
} else { /* unknown code */
SAFECOPY(p->smb.file,base);
p->smb.subnum=INVALID_SUB;
}
}
if(!js_DefineSyncMethods(cx, obj, js_msgbase_functions, FALSE)) {
JS_ReportError(cx,"js_DefineSyncMethods failed");
return(JS_FALSE);
}
return(JS_TRUE);
}
JSObject* DLLCALL js_CreateMsgBaseClass(JSContext* cx, JSObject* parent, scfg_t* cfg)
{
JSObject* obj;
scfg = cfg;
obj = JS_InitClass(cx, parent, NULL
,&js_msgbase_class
,js_msgbase_constructor
,1 /* number of constructor args */
,NULL //js_msgbase_properties
,NULL //js_msgbase_functions
,NULL,NULL);
return(obj);
}