time_t CheckIfAlreadySeen(const char *Facility, StrBuf *guid, time_t now, time_t antiexpire, eCheckType cType, long ccid, long ioid) { time_t InDBTimeStamp = 0; struct UseTable ut; struct cdbdata *cdbut; if (cType != eWrite) { SEEN_syslog(LOG_DEBUG, "Loading [%s]", ChrPtr(guid)); cdbut = cdb_fetch(CDB_USETABLE, SKEY(guid)); if ((cdbut != NULL) && (cdbut->ptr != NULL)) { memcpy(&ut, cdbut->ptr, ((cdbut->len > sizeof(struct UseTable)) ? sizeof(struct UseTable) : cdbut->len)); InDBTimeStamp = now - ut.ut_timestamp; if (InDBTimeStamp < antiexpire) { SEEN_syslog(LOG_DEBUG, "Found - Not expired %ld < %ld", InDBTimeStamp, antiexpire); cdb_free(cdbut); return InDBTimeStamp; } else { SEEN_syslog(LOG_DEBUG, "Found - Expired. %ld >= %ld", InDBTimeStamp, antiexpire); cdb_free(cdbut); } } else { if (cdbut) cdb_free(cdbut); SEENM_syslog(LOG_DEBUG, "not Found"); } if (cType == eCheckExist) return InDBTimeStamp; } memcpy(ut.ut_msgid, SKEY(guid)); ut.ut_timestamp = now; SEENM_syslog(LOG_DEBUG, "Saving new Timestamp"); /* rewrite the record anyway, to update the timestamp */ cdb_store(CDB_USETABLE, SKEY(guid), &ut, sizeof(struct UseTable) ); SEENM_syslog(LOG_DEBUG, "Done Saving"); return InDBTimeStamp; }
// // Utility function to fetch the current list of message numbers in a room // struct nntp_msglist nntp_fetch_msglist(struct ctdlroom *qrbuf) { struct nntp_msglist nm; struct cdbdata *cdbfr; cdbfr = cdb_fetch(CDB_MSGLISTS, &qrbuf->QRnumber, sizeof(long)); if (cdbfr != NULL) { nm.msgnums = (long*)cdbfr->ptr; cdbfr->ptr = NULL; nm.num_msgs = cdbfr->len / sizeof(long); cdbfr->len = 0; cdb_free(cdbfr); } else { nm.num_msgs = 0; nm.msgnums = NULL; } return(nm); }
void cmd_rsen(char *argbuf) { char Token[SIZ]; long TLen; char Time[SIZ]; struct UseTable ut; struct cdbdata *cdbut; if (CtdlAccessCheck(ac_aide)) return; TLen = extract_token(Token, argbuf, 1, '|', sizeof Token); if (strncmp(argbuf, "GET", 3) == 0) { cdbut = cdb_fetch(CDB_USETABLE, Token, TLen); if (cdbut != NULL) { memcpy(&ut, cdbut->ptr, ((cdbut->len > sizeof(struct UseTable)) ? sizeof(struct UseTable) : cdbut->len)); cprintf("%d %ld\n", CIT_OK, ut.ut_timestamp); } else { cprintf("%d not found\n", ERROR + NOT_HERE); } } else if (strncmp(argbuf, "SET", 3) == 0) { memcpy(ut.ut_msgid, Token, TLen); extract_token(Time, argbuf, 2, '|', sizeof Time); ut.ut_timestamp = atol(Time); cdb_store(CDB_USETABLE, Token, TLen, &ut, sizeof(struct UseTable) ); cprintf("%d token updated\n", CIT_OK); } else if (strncmp(argbuf, "DEL", 3) == 0) { if (cdb_delete(CDB_USETABLE, Token, TLen)) cprintf("%d not found\n", ERROR + NOT_HERE); else cprintf("%d deleted.\n", CIT_OK); } else { cprintf("%d Usage: [GET|SET|DEL]|Token|timestamp\n", ERROR); } }
/* * Attach an OpenID to a Citadel account */ int attach_openid(struct ctdluser *who, StrBuf *claimed_id) { struct cdbdata *cdboi; long fetched_usernum; char *data; int data_len; char buf[2048]; if (!who) return(1); if (StrLength(claimed_id)==0) return(1); /* Check to see if this OpenID is already in the database */ cdboi = cdb_fetch(CDB_OPENID, ChrPtr(claimed_id), StrLength(claimed_id)); if (cdboi != NULL) { memcpy(&fetched_usernum, cdboi->ptr, sizeof(long)); cdb_free(cdboi); if (fetched_usernum == who->usernum) { syslog(LOG_INFO, "%s already associated; no action is taken", ChrPtr(claimed_id)); return(0); } else { syslog(LOG_INFO, "%s already belongs to another user", ChrPtr(claimed_id)); return(3); } } /* Not already in the database, so attach it now */ data_len = sizeof(long) + StrLength(claimed_id) + 1; data = malloc(data_len); memcpy(data, &who->usernum, sizeof(long)); memcpy(&data[sizeof(long)], ChrPtr(claimed_id), StrLength(claimed_id) + 1); cdb_store(CDB_OPENID, ChrPtr(claimed_id), StrLength(claimed_id), data, data_len); free(data); snprintf(buf, sizeof buf, "User <%s> (#%ld) has claimed the OpenID URL %s\n", who->fullname, who->usernum, ChrPtr(claimed_id)); CtdlAideMessage(buf, "OpenID claim"); syslog(LOG_INFO, "%s", buf); return(0); }
/* * callback to get highest room number when rebuilding control file */ void control_find_highest(struct ctdlroom *qrbuf, void *data) { struct ctdlroom room; struct cdbdata *cdbfr; long *msglist; int num_msgs=0; int c; int room_fixed = 0; int message_fixed = 0; if (qrbuf->QRnumber > CitControl.MMnextroom) { CitControl.MMnextroom = qrbuf->QRnumber; room_fixed = 1; } CtdlGetRoom (&room, qrbuf->QRname); /* Load the message list */ cdbfr = cdb_fetch(CDB_MSGLISTS, &room.QRnumber, sizeof(long)); if (cdbfr != NULL) { msglist = (long *) cdbfr->ptr; num_msgs = cdbfr->len / sizeof(long); } else { return; /* No messages at all? No further action. */ } if (num_msgs>0) { for (c=0; c<num_msgs; c++) { if (msglist[c] > CitControl.MMhighest) { CitControl.MMhighest = msglist[c]; message_fixed = 1; } } } cdb_free(cdbfr); if (room_fixed) syslog(LOG_INFO, "Control record checking....Fixed room counter\n"); if (message_fixed) syslog(LOG_INFO, "Control record checking....Fixed message count\n"); return; }
/* * Look up an Internet e-mail address in the directory. * On success: returns 0, and Citadel address stored in 'target' * On failure: returns nonzero */ int CtdlDirectoryLookup(char *target, char *internet_addr, size_t targbuflen) { struct cdbdata *cdbrec; char key[SIZ]; /* Dump it in there unchanged, just for kicks */ safestrncpy(target, internet_addr, targbuflen); /* Only do lookups for addresses with hostnames in them */ if (num_tokens(internet_addr, '@') != 2) return(-1); /* Only do lookups for domains in the directory */ if (IsDirectory(internet_addr, 0) == 0) return(-1); directory_key(key, internet_addr); cdbrec = cdb_fetch(CDB_DIRECTORY, key, strlen(key) ); if (cdbrec != NULL) { safestrncpy(target, cdbrec->ptr, targbuflen); cdb_free(cdbrec); return(0); } return(-1); }
/* * If a user account exists which is associated with the Claimed ID, log it in and return zero. * Otherwise it returns nonzero. */ int login_via_openid(StrBuf *claimed_id) { struct cdbdata *cdboi; long usernum = 0; cdboi = cdb_fetch(CDB_OPENID, ChrPtr(claimed_id), StrLength(claimed_id)); if (cdboi == NULL) { return(-1); } memcpy(&usernum, cdboi->ptr, sizeof(long)); cdb_free(cdboi); if (!CtdlGetUserByNumber(&CC->user, usernum)) { /* Now become the user we just created */ safestrncpy(CC->curr_user, CC->user.fullname, sizeof CC->curr_user); do_login(); return(0); } else { memset(&CC->user, 0, sizeof(struct ctdluser)); return(-1); } }
/* * First phase of message purge -- gather the locations of messages which * qualify for purging and write them to a temp file. */ void GatherPurgeMessages(struct ctdlroom *qrbuf, void *data) { struct ExpirePolicy epbuf; long delnum; time_t xtime, now; struct CtdlMessage *msg = NULL; int a; struct cdbdata *cdbfr; long *msglist = NULL; int num_msgs = 0; FILE *purgelist; purgelist = (FILE *)data; fprintf(purgelist, "r=%s\n", qrbuf->QRname); time(&now); GetExpirePolicy(&epbuf, qrbuf); /* If the room is set to never expire messages ... do nothing */ if (epbuf.expire_mode == EXPIRE_NEXTLEVEL) return; if (epbuf.expire_mode == EXPIRE_MANUAL) return; /* Don't purge messages containing system configuration, dumbass. */ if (!strcasecmp(qrbuf->QRname, SYSCONFIGROOM)) return; /* Ok, we got this far ... now let's see what's in the room */ cdbfr = cdb_fetch(CDB_MSGLISTS, &qrbuf->QRnumber, sizeof(long)); if (cdbfr != NULL) { msglist = malloc(cdbfr->len); memcpy(msglist, cdbfr->ptr, cdbfr->len); num_msgs = cdbfr->len / sizeof(long); cdb_free(cdbfr); } /* Nothing to do if there aren't any messages */ if (num_msgs == 0) { if (msglist != NULL) free(msglist); return; } /* If the room is set to expire by count, do that */ if (epbuf.expire_mode == EXPIRE_NUMMSGS) { if (num_msgs > epbuf.expire_value) { for (a=0; a<(num_msgs - epbuf.expire_value); ++a) { fprintf(purgelist, "m=%ld\n", msglist[a]); ++messages_purged; } } } /* If the room is set to expire by age... */ if (epbuf.expire_mode == EXPIRE_AGE) { for (a=0; a<num_msgs; ++a) { delnum = msglist[a]; msg = CtdlFetchMessage(delnum, 0); /* dont need body */ if (msg != NULL) { xtime = atol(msg->cm_fields[eTimestamp]); CM_Free(msg); } else { xtime = 0L; } if ((xtime > 0L) && (now - xtime > (time_t)(epbuf.expire_value * 86400L))) { fprintf(purgelist, "m=%ld\n", delnum); ++messages_purged; } } } if (msglist != NULL) free(msglist); }
/* * API call to perform searches. * (This one does the "all of these words" search.) * Caller is responsible for freeing the message list. */ void ft_search(int *fts_num_msgs, long **fts_msgs, const char *search_string) { int num_tokens = 0; int *tokens = NULL; int i, j; struct cdbdata *cdb_bucket; int num_all_msgs = 0; long *all_msgs = NULL; int num_ret_msgs = 0; int num_ret_alloc = 0; long *ret_msgs = NULL; int tok; wordbreaker(search_string, &num_tokens, &tokens); if (num_tokens > 0) { for (i=0; i<num_tokens; ++i) { /* search for tokens[i] */ tok = tokens[i]; /* fetch the bucket, Liza */ if (ftc_msgs[tok] == NULL) { cdb_bucket = cdb_fetch(CDB_FULLTEXT, &tok, sizeof(int)); if (cdb_bucket != NULL) { ftc_num_msgs[tok] = cdb_bucket->len / sizeof(long); ftc_msgs[tok] = (long *)cdb_bucket->ptr; cdb_bucket->ptr = NULL; cdb_free(cdb_bucket); } else { ftc_num_msgs[tok] = 0; ftc_msgs[tok] = malloc(sizeof(long)); } } num_all_msgs += ftc_num_msgs[tok]; if (num_all_msgs > 0) { all_msgs = realloc(all_msgs, num_all_msgs*sizeof(long) ); memcpy(&all_msgs[num_all_msgs-ftc_num_msgs[tok]], ftc_msgs[tok], ftc_num_msgs[tok]*sizeof(long) ); } } free(tokens); if (all_msgs != NULL) { qsort(all_msgs, num_all_msgs, sizeof(long), longcmp); /* * At this point, if a message appears num_tokens times in the * list, then it contains all of the search tokens. */ if (num_all_msgs >= num_tokens) for (j=0; j<(num_all_msgs-num_tokens+1); ++j) { if (all_msgs[j] == all_msgs[j+num_tokens-1]) { ++num_ret_msgs; if (num_ret_msgs > num_ret_alloc) { num_ret_alloc += 64; ret_msgs = realloc(ret_msgs, (num_ret_alloc*sizeof(long)) ); } ret_msgs[num_ret_msgs - 1] = all_msgs[j]; } } free(all_msgs); } } *fts_num_msgs = num_ret_msgs; *fts_msgs = ret_msgs; }
/* * Index or de-index a message. (op == 1 to index, 0 to de-index) */ void ft_index_message(long msgnum, int op) { int num_tokens = 0; int *tokens = NULL; int i, j; struct cdbdata *cdb_bucket; StrBuf *msgtext; char *txt; int tok; struct CtdlMessage *msg = NULL; msg = CtdlFetchMessage(msgnum, 1, 1); if (msg == NULL) { syslog(LOG_ERR, "ft_index_message() could not load msg %ld", msgnum); return; } if (!CM_IsEmpty(msg, eSuppressIdx)) { syslog(LOG_DEBUG, "ft_index_message() excluded msg %ld", msgnum); CM_Free(msg); return; } syslog(LOG_DEBUG, "ft_index_message() %s msg %ld", (op ? "adding" : "removing") , msgnum); /* Output the message as text before indexing it, so we don't end up * indexing a bunch of encoded base64, etc. */ CC->redirect_buffer = NewStrBufPlain(NULL, SIZ); CtdlOutputPreLoadedMsg(msg, MT_CITADEL, HEADERS_ALL, 0, 1, 0); CM_Free(msg); msgtext = CC->redirect_buffer; CC->redirect_buffer = NULL; if (msgtext != NULL) { syslog(LOG_DEBUG, "Wordbreaking message %ld (%d bytes)", msgnum, StrLength(msgtext)); } txt = SmashStrBuf(&msgtext); wordbreaker(txt, &num_tokens, &tokens); free(txt); syslog(LOG_DEBUG, "Indexing message %ld [%d tokens]", msgnum, num_tokens); if (num_tokens > 0) { for (i=0; i<num_tokens; ++i) { /* Add the message to the relevant token bucket */ /* search for tokens[i] */ tok = tokens[i]; if ( (tok >= 0) && (tok <= 65535) ) { /* fetch the bucket, Liza */ if (ftc_msgs[tok] == NULL) { cdb_bucket = cdb_fetch(CDB_FULLTEXT, &tok, sizeof(int)); if (cdb_bucket != NULL) { ftc_num_msgs[tok] = cdb_bucket->len / sizeof(long); ftc_msgs[tok] = (long *)cdb_bucket->ptr; cdb_bucket->ptr = NULL; cdb_free(cdb_bucket); } else { ftc_num_msgs[tok] = 0; ftc_msgs[tok] = malloc(sizeof(long)); } } if (op == 1) { /* add to index */ ++ftc_num_msgs[tok]; ftc_msgs[tok] = realloc(ftc_msgs[tok], ftc_num_msgs[tok]*sizeof(long)); ftc_msgs[tok][ftc_num_msgs[tok] - 1] = msgnum; } if (op == 0) { /* remove from index */ if (ftc_num_msgs[tok] >= 1) { for (j=0; j<ftc_num_msgs[tok]; ++j) { if (ftc_msgs[tok][j] == msgnum) { memmove(&ftc_msgs[tok][j], &ftc_msgs[tok][j+1], ((ftc_num_msgs[tok] - j - 1)*sizeof(long))); --ftc_num_msgs[tok]; --j; } } } } } else { syslog(LOG_ALERT, "Invalid token %d !!", tok); } } free(tokens); } }
/* * Attempt to autocomplete an address based on a partial... */ void cmd_auto(char *argbuf) { char hold_rm[ROOMNAMELEN]; char search_string[256]; long *msglist = NULL; int num_msgs = 0; long *fts_msgs = NULL; int fts_num_msgs = 0; struct cdbdata *cdbfr; int r = 0; int i = 0; int j = 0; int search_match = 0; char *rooms_to_try[] = { USERCONTACTSROOM, ADDRESS_BOOK_ROOM }; if (CtdlAccessCheck(ac_logged_in)) return; extract_token(search_string, argbuf, 0, '|', sizeof search_string); if (IsEmptyStr(search_string)) { cprintf("%d You supplied an empty partial.\n", ERROR + ILLEGAL_VALUE); return; } strcpy(hold_rm, CC->room.QRname); /* save current room */ cprintf("%d try these:\n", LISTING_FOLLOWS); /* * Gather up message pointers in rooms containing vCards */ for (r=0; r < (sizeof(rooms_to_try) / sizeof(char *)); ++r) { if (CtdlGetRoom(&CC->room, rooms_to_try[r]) == 0) { cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long)); if (cdbfr != NULL) { msglist = realloc(msglist, (num_msgs * sizeof(long)) + cdbfr->len + 1); memcpy(&msglist[num_msgs], cdbfr->ptr, cdbfr->len); num_msgs += (cdbfr->len / sizeof(long)); cdb_free(cdbfr); } } } /* * Search-reduce the results if we have the full text index available */ if (config.c_enable_fulltext) { CtdlModuleDoSearch(&fts_num_msgs, &fts_msgs, search_string, "fulltext"); if (fts_msgs) { for (i=0; i<num_msgs; ++i) { search_match = 0; for (j=0; j<fts_num_msgs; ++j) { if (msglist[i] == fts_msgs[j]) { search_match = 1; j = fts_num_msgs + 1; /* end the search */ } } if (!search_match) { msglist[i] = 0; /* invalidate this result */ } } free(fts_msgs); } else { /* If no results, invalidate the whole list */ free(msglist); msglist = NULL; num_msgs = 0; } } /* * Now output the ones that look interesting */ if (num_msgs > 0) for (i=0; i<num_msgs; ++i) { if (msglist[i] != 0) { hunt_for_autocomplete(msglist[i], search_string); } } cprintf("000\n"); if (strcmp(CC->room.QRname, hold_rm)) { CtdlGetRoom(&CC->room, hold_rm); /* return to saved room */ } if (msglist) { free(msglist); } }