summaryrefslogtreecommitdiff
path: root/data.c
diff options
context:
space:
mode:
Diffstat (limited to 'data.c')
-rw-r--r--data.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/data.c b/data.c
index 4e1682c..d9449d8 100644
--- a/data.c
+++ b/data.c
@@ -2488,6 +2488,113 @@ void notify_clear(snac *snac)
}
+/** searches **/
+
+xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, int *timeout)
+/* returns a list of posts which content matches the regex */
+{
+ xs_set seen;
+
+ xs_set_init(&seen);
+
+ if (max_secs == 0)
+ max_secs = 3;
+
+ time_t t = time(NULL) + max_secs;
+ *timeout = 0;
+
+ /* iterate both timelines simultaneously */
+ xs *pub_tl = timeline_simple_list(user, "public", 0, XS_ALL);
+ int pub_c = 0;
+ char *pub_md5 = NULL;
+
+ xs *priv_tl = priv ? timeline_simple_list(user, "private", 0, XS_ALL) : xs_list_new();
+ int priv_c = 0;
+ char *priv_md5 = NULL;
+
+ /* first positioning */
+ xs_list_next(pub_tl, &pub_md5, &pub_c);
+ xs_list_next(priv_tl, &priv_md5, &priv_c);
+
+ for (;;) {
+ char *md5 = NULL;
+ enum { NONE, PUBLIC, PRIVATE } from = NONE;
+
+ /* timeout? */
+ if (time(NULL) > t) {
+ *timeout = 1;
+ break;
+ }
+
+ if (pub_md5 == NULL) {
+ /* out of both lists? done */
+ if (priv_md5 == NULL)
+ break;
+
+ /* out of public: take element from the private timeline and advance */
+ from = PRIVATE;
+ }
+ else
+ if (priv_md5 == NULL) {
+ /* out of private: take element from the public timeline and advance */
+ from = PUBLIC;
+ }
+ else {
+ /* candidates from both: choose one from the file dates */
+ xs *pub_fn = xs_fmt("%s/public/%s.json", user->basedir, pub_md5);
+ xs *priv_fn = xs_fmt("%s/private/%s.json", user->basedir, priv_md5);
+
+ if (mtime(pub_fn) < mtime(priv_fn))
+ from = PRIVATE;
+ else
+ from = PUBLIC;
+ }
+
+ if (from == PUBLIC) { /* public */
+ md5 = pub_md5;
+ if (!xs_list_next(pub_tl, &pub_md5, &pub_c))
+ pub_md5 = NULL;
+ }
+ else
+ if (from == PRIVATE) { /* private */
+ md5 = priv_md5;
+ if (!xs_list_next(priv_tl, &priv_md5, &priv_c))
+ priv_md5 = NULL;
+ }
+
+ if (md5 == NULL)
+ break;
+
+ xs *post = NULL;
+
+ if (!valid_status(timeline_get_by_md5(user, md5, &post)))
+ continue;
+
+ /* must be a Note */
+ if (strcmp(xs_dict_get_def(post, "type", ""), "Note"))
+ continue;
+
+ char *content = xs_dict_get(post, "content");
+
+ if (xs_is_null(content))
+ continue;
+
+ /* strip HTML */
+ xs *c = xs_regex_replace(content, "<[^>]+>", " ");
+ c = xs_regex_replace_i(c, " {2,}", " ");
+ c = xs_tolower_i(c);
+
+ /* apply regex */
+ xs *l = xs_regex_select_n(c, regex, 1);
+
+ if (xs_list_len(l))
+ xs_set_add(&seen, md5);
+ }
+
+ return xs_set_result(&seen);
+}
+
+
/** the queue **/
static xs_dict *_enqueue_put(const char *fn, xs_dict *msg)