Commit 75417a26 authored by rswindell's avatar rswindell
Browse files

New MsgBase method: get_index() - returns an array of all message index records

(objects, in the same format as returned by the get_mgs_index() method)
much faster than iterating through a loop, calling the get_msg_index() method
for each message. If you want to load messages (e.g. headers, text), filtering
by criteria found in the message index (attributes, to/from user, subject CRC)
loading a list of indexes and filtering before calling get_msg_header() for the
selected messages is much faster than previously available MsgBase object
methods (e.g. get_all_msg_headers()). If you don't need to filter the loaded
messages (you really want *all* message headers), then get_index() is of no
benefit to you, the script-writer. This is most useful for the "mail" msgbase
where selective loading of messages is more common.
parent 0a5ea2e4
......@@ -37,6 +37,7 @@
#include "sbbs.h"
#include "js_request.h"
#include "userdat.h"
#include <stdbool.h>
#ifdef JAVASCRIPT
......@@ -986,6 +987,60 @@ static BOOL msg_offset_by_id(private_t* p, char* id, int32_t* offset)
return(TRUE);
}
static bool set_msg_idx_properties(JSContext* cx, JSObject* obj, idxrec_t* idx, int32_t offset)
{
jsval val;
val = UINT_TO_JSVAL(idx->number);
if(!JS_DefineProperty(cx, obj, "number" ,val
,NULL,NULL,JSPROP_ENUMERATE))
return false;
if(idx->attr&MSG_VOTE && !(idx->attr&MSG_POLL)) {
val=UINT_TO_JSVAL(idx->votes);
if(!JS_DefineProperty(cx, obj, "votes" ,val
,NULL,NULL,JSPROP_ENUMERATE))
return false;
val=UINT_TO_JSVAL(idx->remsg);
if(!JS_DefineProperty(cx, obj, "remsg" ,val
,NULL,NULL,JSPROP_ENUMERATE))
return false;
} else { /* normal message */
val=UINT_TO_JSVAL(idx->to);
if(!JS_DefineProperty(cx, obj, "to" ,val
,NULL,NULL,JSPROP_ENUMERATE))
return false;
val=UINT_TO_JSVAL(idx->from);
if(!JS_DefineProperty(cx, obj, "from" ,val
,NULL,NULL,JSPROP_ENUMERATE))
return false;
val=UINT_TO_JSVAL(idx->subj);
if(!JS_DefineProperty(cx, obj, "subject" ,val
,NULL,NULL,JSPROP_ENUMERATE))
return false;
}
val=UINT_TO_JSVAL(idx->attr);
if(!JS_DefineProperty(cx, obj, "attr" ,val
,NULL,NULL,JSPROP_ENUMERATE))
return false;
// confusingly, this is the msg.offset, not the idx.offset value
val=INT_TO_JSVAL(offset);
if(!JS_DefineProperty(cx, obj, "offset" ,val
,NULL,NULL,JSPROP_ENUMERATE))
return false;
val=UINT_TO_JSVAL(idx->time);
if(!JS_DefineProperty(cx, obj, "time" ,val
,NULL,NULL,JSPROP_ENUMERATE))
return false;
return true;
}
static JSBool
js_get_msg_index(JSContext *cx, uintN argc, jsval *arglist)
{
......@@ -1054,48 +1109,84 @@ js_get_msg_index(JSContext *cx, uintN argc, jsval *arglist)
if((idxobj=JS_NewObject(cx,NULL,proto,obj))==NULL)
return JS_TRUE;
val=UINT_TO_JSVAL(msg.idx.number);
JS_DefineProperty(cx, idxobj, "number" ,val
,NULL,NULL,JSPROP_ENUMERATE);
set_msg_idx_properties(cx, idxobj, &msg.idx, msg.offset);
if(msg.idx.attr&MSG_VOTE && !(msg.idx.attr&MSG_POLL)) {
val=UINT_TO_JSVAL(msg.idx.votes);
JS_DefineProperty(cx, idxobj, "votes" ,val
,NULL,NULL,JSPROP_ENUMERATE);
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(idxobj));
val=UINT_TO_JSVAL(msg.idx.remsg);
JS_DefineProperty(cx, idxobj, "remsg" ,val
,NULL,NULL,JSPROP_ENUMERATE);
} else { /* normal message */
val=UINT_TO_JSVAL(msg.idx.to);
JS_DefineProperty(cx, idxobj, "to" ,val
,NULL,NULL,JSPROP_ENUMERATE);
return JS_TRUE;
}
val=UINT_TO_JSVAL(msg.idx.from);
JS_DefineProperty(cx, idxobj, "from" ,val
,NULL,NULL,JSPROP_ENUMERATE);
static JSBool
js_get_index(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject* obj=JS_THIS_OBJECT(cx, arglist);
jsval* argv=JS_ARGV(cx, arglist);
jsrefcount rc;
private_t* priv;
uint32_t off;
JSObject* array;
idxrec_t* idx;
if((array = JS_NewArrayObject(cx, 0, NULL)) == NULL)
return JS_FALSE;
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
val=UINT_TO_JSVAL(msg.idx.subj);
JS_DefineProperty(cx, idxobj, "subject" ,val
,NULL,NULL,JSPROP_ENUMERATE);
if((priv=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
JS_ReportError(cx,getprivate_failure,WHERE);
return JS_FALSE;
}
val=UINT_TO_JSVAL(msg.idx.attr);
JS_DefineProperty(cx, idxobj, "attr" ,val
,NULL,NULL,JSPROP_ENUMERATE);
val=UINT_TO_JSVAL(msg.offset);
JS_DefineProperty(cx, idxobj, "offset" ,val
,NULL,NULL,JSPROP_ENUMERATE);
if(!SMB_IS_OPEN(&(priv->smb)))
return JS_TRUE;
val=UINT_TO_JSVAL(msg.idx.time);
JS_DefineProperty(cx, idxobj, "time" ,val
,NULL,NULL,JSPROP_ENUMERATE);
off_t index_length = filelength(fileno(priv->smb.sid_fp));
if(index_length < sizeof(*idx))
return JS_TRUE;
uint32_t total_msgs = index_length / sizeof(*idx);
if(total_msgs > priv->smb.status.total_msgs)
total_msgs = priv->smb.status.total_msgs;
if(total_msgs < 1)
return JS_TRUE;
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(idxobj));
if((idx = calloc(total_msgs, sizeof(*idx))) == NULL) {
JS_ReportError(cx, "malloc error", WHERE);
return JS_FALSE;
}
rc=JS_SUSPENDREQUEST(cx);
if((priv->smb_result = smb_locksmbhdr(&(priv->smb))) != SMB_SUCCESS) {
JS_RESUMEREQUEST(cx, rc);
free(idx);
return JS_TRUE;
}
rewind(priv->smb.sid_fp);
size_t fread_result = fread(idx, sizeof(*idx), total_msgs, priv->smb.sid_fp);
smb_unlocksmbhdr(&(priv->smb));
JS_RESUMEREQUEST(cx, rc);
if(fread_result != total_msgs) {
JS_ReportError(cx, "index read failed (%lu instead of %lu)", fread_result, total_msgs);
free(idx);
return JS_FALSE;
}
for(off=0; off < total_msgs; off++) {
JSObject* idxobj;
if((idxobj = JS_NewObject(cx, NULL, NULL, array)) == NULL) {
JS_ReportError(cx, "object allocation failure, line %d", __LINE__);
free(idx);
return JS_FALSE;
}
set_msg_idx_properties(cx, idxobj, &idx[off], off);
JS_DefineElement(cx, array, off, OBJECT_TO_JSVAL(idxobj), NULL, NULL, JSPROP_ENUMERATE);
}
free(idx);
return JS_TRUE;
}
#define LAZY_INTEGER(PropName, PropValue, flags) \
if(name==NULL || strcmp(name, (PropName))==0) { \
if(name) free(name); \
......@@ -1730,7 +1821,6 @@ js_get_all_msg_headers(JSContext *cx, uintN argc, jsval *arglist)
free(idx);
return JS_TRUE;
}
JS_RESUMEREQUEST(cx, rc);
if(JS_GetProperty(cx, JS_GetGlobalObject(cx), "MsgBase", &val) && !JSVAL_NULL_OR_VOID(val)) {
JS_ValueToObject(cx,val,&proto);
......@@ -1744,6 +1834,8 @@ js_get_all_msg_headers(JSContext *cx, uintN argc, jsval *arglist)
rewind(priv->smb.sid_fp);
size_t fread_result = fread(idx, sizeof(*idx), total_msgs, priv->smb.sid_fp);
JS_RESUMEREQUEST(cx, rc);
if(fread_result != total_msgs) {
smb_unlocksmbhdr(&(priv->smb));
JS_ReportError(cx,"index read failed (%lu instead of %lu)", fread_result, total_msgs);
......@@ -2882,8 +2974,8 @@ 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>] [,expand_fields=<tt>true</tt>]")
,JSDOCSTR("returns an object of all message headers indexed by message number.<br>"
{"get_all_msg_headers", js_get_all_msg_headers, 1, JSTYPE_OBJECT, JSDOCSTR("[include_votes=<tt>false</tt>] [,expand_fields=<tt>true</tt>]")
,JSDOCSTR("returns an object (associative array) 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
......@@ -2908,7 +3000,7 @@ static jsSyncMethodSpec js_msgbase_functions[] = {
,310
},
{"get_msg_index", js_get_msg_index, 3, JSTYPE_OBJECT, JSDOCSTR("[by_offset=<tt>false</tt>,] number_or_offset, [include_votes=<tt>false</tt>]")
,JSDOCSTR("returns a specific message index, <i>null</i> on failure. "
,JSDOCSTR("returns a specific message index record, <i>null</i> on failure. "
"The index object will contain the following properties:<br>"
"<table>"
"<tr><td align=top><tt>attr</tt><td>Attribute bitfield"
......@@ -2930,6 +3022,12 @@ static jsSyncMethodSpec js_msgbase_functions[] = {
)
,311
},
{"get_index", js_get_index, 0, JSTYPE_ARRAY, JSDOCSTR("")
,JSDOCSTR("return an array of message index records represented as objects, the same format as returned by <i>get_msg_index()</i>"
"<br>"
"This is the fastest method of obtaining a list of all message index records.")
,31702
},
{"remove_msg", js_remove_msg, 2, JSTYPE_BOOLEAN, JSDOCSTR("[by_offset=<tt>false</tt>,] number_or_offset_or_id")
,JSDOCSTR("mark message for deletion")
,311
......@@ -3141,7 +3239,7 @@ js_msgbase_constructor(JSContext *cx, uintN argc, jsval *arglist)
"The MsgBase retrieval methods that accept a <tt>by_offset</tt> argument as their optional first boolean argument "
"will interpret the following <i>number</i> argument as either a 1-based unique message number (by_offset=<tt>false</tt>) "
"or a 0-based message index-offset (by_offset=<tt>true</tt>). Retrieving messages by offset is faster than by number or "
"message-id (string). Passing an existing message header to the retrieval methods that support it (e.g. <tt>get_msg_body()</tt>) "
"message-id (string). Passing an existing message <i>header object</i> to the retrieval methods that support it (e.g. <tt>get_msg_body()</tt>) "
"is even faster. "
);
js_CreateArrayOfStrings(cx, obj, "_property_desc_list", msgbase_prop_desc, JSPROP_READONLY);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment