From 3148ead09dae3e163ef474f11ad34e7097d4839b Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Sat, 9 Apr 2016 19:54:36 -0400 Subject: [PATCH] User profiles (bios) are now stored as MIME in the user config room. If a bio/ directory exists it is ingested at startup and deleted. --- citadel/citadel.h | 2 + citadel/modules/bio/serv_bio.c | 146 ++++++++++++++++--------- citadel/modules/migrate/serv_migrate.c | 6 +- citadel/msgbase.c | 10 +- citadel/msgbase.h | 8 +- citadel/user_ops.c | 10 +- citadel/utillib/citadel_dirs.c | 2 - citadel/utils/ctdlmigrate.c | 6 +- 8 files changed, 113 insertions(+), 77 deletions(-) diff --git a/citadel/citadel.h b/citadel/citadel.h index 047acb6c8..96422ac96 100644 --- a/citadel/citadel.h +++ b/citadel/citadel.h @@ -113,6 +113,8 @@ struct ctdluser { /* User record */ time_t lastcall; /* Date/time of most recent login */ int USuserpurge; /* Purge time (in days) for user */ char fullname[64]; /* Display name (primary identifier) */ + long msgnum_bio; /* msgnum of user's profile (bio) */ + long msgnum_pic; /* msgnum of user's avatar (photo) */ }; diff --git a/citadel/modules/bio/serv_bio.c b/citadel/modules/bio/serv_bio.c index 81a54b573..071df1113 100644 --- a/citadel/modules/bio/serv_bio.c +++ b/citadel/modules/bio/serv_bio.c @@ -2,7 +2,7 @@ * This module implementsserver commands related to the display and * manipulation of user "bio" files. * - * Copyright (c) 1987-2015 by the citadel.org team + * Copyright (c) 1987-2016 by the citadel.org team * * This program is open source software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,92 +24,149 @@ /* - * enter user bio + * Command to enter user bio (profile) in plain text. + * This is deprecated , or at least it will be when its replacement is written :) + * I want commands to get/set bio in full MIME wonderfulness. */ void cmd_ebio(char *cmdbuf) { char buf[SIZ]; - FILE *fp; unbuffer_output(); if (!(CC->logged_in)) { - cprintf("%d Not logged in.\n",ERROR + NOT_LOGGED_IN); + cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN); return; } - snprintf(buf, sizeof buf, "%s%ld",ctdl_bio_dir,CC->user.usernum); - fp = fopen(buf,"w"); - if (fp == NULL) { - cprintf("%d Cannot create file: %s\n", ERROR + INTERNAL_ERROR, - strerror(errno)); - return; - } - cprintf("%d \n",SEND_LISTING); + StrBuf *NewProfile = NewStrBufPlain("Content-type: text/plain; charset=UTF-8\nContent-transfer-encoding: 8bit\n\n", -1); + + cprintf("%d Transmit user profile in plain text now.\n", SEND_LISTING); while(client_getln(buf, sizeof buf) >= 0 && strcmp(buf,"000")) { - if (ftell(fp) < CtdlGetConfigLong("c_maxmsglen")) { - fprintf(fp,"%s\n",buf); - } + StrBufAppendBufPlain(NewProfile, buf, -1, 0); + StrBufAppendBufPlain(NewProfile, HKEY("\n"), 0); } - fclose(fp); + + /* we have read the new profile from the user , now save it */ + long old_msgnum = CC->user.msgnum_bio; + char userconfigroomname[ROOMNAMELEN]; + CtdlMailboxName(userconfigroomname, sizeof userconfigroomname, &CC->user, USERCONFIGROOM); + long new_msgnum = quickie_message("Citadel", NULL, NULL, userconfigroomname, ChrPtr(NewProfile), FMT_RFC822, "Profile submitted with EBIO command"); + CtdlGetUserLock(&CC->user, CC->curr_user); + CC->user.msgnum_bio = new_msgnum; + CtdlPutUserLock(&CC->user); + if (old_msgnum > 0) { + syslog(LOG_DEBUG, "Deleting old message %ld from %s", old_msgnum, userconfigroomname); + CtdlDeleteMessages(userconfigroomname, &old_msgnum, 1, ""); + } + + FreeStrBuf(&NewProfile); } + /* - * read user bio + * Command to read user bio (profile) in plain text. + * This is deprecated , or at least it will be when its replacement is written :) + * I want commands to get/set bio in full MIME wonderfulness. */ void cmd_rbio(char *cmdbuf) { struct ctdluser ruser; - char buf[256]; - FILE *fp; + char buf[SIZ]; extract_token(buf, cmdbuf, 0, '|', sizeof buf); if (CtdlGetUser(&ruser, buf) != 0) { cprintf("%d No such user.\n",ERROR + NO_SUCH_USER); return; } - snprintf(buf, sizeof buf, "%s%ld",ctdl_bio_dir,ruser.usernum); - + cprintf("%d OK|%s|%ld|%d|%ld|%ld|%ld\n", LISTING_FOLLOWS, ruser.fullname, ruser.usernum, ruser.axlevel, (long)ruser.lastcall, ruser.timescalled, ruser.posted); - fp = fopen(buf,"r"); - if (fp == NULL) - cprintf("%s has no bio on file.\n", ruser.fullname); - else { - while (fgets(buf, sizeof buf, fp) != NULL) cprintf("%s",buf); - fclose(fp); + + struct CtdlMessage *msg = CtdlFetchMessage(ruser.msgnum_bio, 1, 1); + if (msg != NULL) { + CtdlOutputPreLoadedMsg(msg, MT_CITADEL, HEADERS_NONE, 0, 0, 0); + CM_Free(msg); } cprintf("000\n"); } + /* - * list of users who have entered bios + * Import function called by import_old_bio_files() for a single user */ -void cmd_lbio(char *cmdbuf) +void import_one_bio_file(char *username, long usernum, char *path) +{ + syslog(LOG_DEBUG, "Import legacy bio for %s, usernum=%ld, filename=%s", username, usernum, path); + + FILE *fp = fopen(path, "r"); + if (!fp) return; + + fseek(fp, 0, SEEK_END); + long data_length = ftell(fp); + + if (data_length >= 1) { + rewind(fp); + char *unencoded_data = malloc(data_length); + if (unencoded_data) { + fread(unencoded_data, data_length, 1, fp); + char *encoded_data = malloc((data_length * 2) + 100); + if (encoded_data) { + sprintf(encoded_data, "Content-type: text/plain; charset=UTF-8\nContent-transfer-encoding: base64\n\n"); + CtdlEncodeBase64(&encoded_data[strlen(encoded_data)], unencoded_data, data_length, 1); + + char userconfigroomname[ROOMNAMELEN]; + struct ctdluser usbuf; + + if (CtdlGetUser(&usbuf, username) == 0) { // no need to lock it , we are still initializing + long old_msgnum = usbuf.msgnum_bio; + CtdlMailboxName(userconfigroomname, sizeof userconfigroomname, &usbuf, USERCONFIGROOM); + long new_msgnum = quickie_message("Citadel", NULL, NULL, userconfigroomname, encoded_data, FMT_RFC822, "Profile imported from bio"); + syslog(LOG_DEBUG, "Message %ld is now the profile for %s", new_msgnum, username); + usbuf.msgnum_bio = new_msgnum; + CtdlPutUser(&usbuf); + unlink(path); // delete the old file , it's in the database now + if (old_msgnum > 0) { + syslog(LOG_DEBUG, "Deleting old message %ld from %s", old_msgnum, userconfigroomname); + CtdlDeleteMessages(userconfigroomname, &old_msgnum, 1, ""); + } + } + free(encoded_data); + } + free(unencoded_data); + } + } + fclose(fp); +} + + +/* + * Look for old-format "bio" files and import them into the message base + */ +void import_old_bio_files(void) { DIR *filedir = NULL; struct dirent *filedir_entry; struct dirent *d; - int dont_resolve_uids; size_t d_namelen; struct ctdluser usbuf; + long usernum = 0; int d_type = 0; + struct stat s; + char path[PATH_MAX]; + syslog(LOG_DEBUG, "Importing old style bio files into the message base"); d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 2); if (d == NULL) { - cprintf("%d Cannot open listing.\n", ERROR + FILE_NOT_FOUND); return; } filedir = opendir (ctdl_bio_dir); if (filedir == NULL) { free(d); - cprintf("%d Cannot open listing.\n", ERROR + FILE_NOT_FOUND); return; } - dont_resolve_uids = *cmdbuf == '1'; - cprintf("%d\n", LISTING_FOLLOWS); while ((readdir_r(filedir, d, &filedir_entry) == 0) && (filedir_entry != NULL)) { @@ -144,11 +201,8 @@ void cmd_lbio(char *cmdbuf) (filedir_entry->d_name[1] == '.')) continue; + snprintf(path, PATH_MAX, "%s/%s", ctdl_bio_dir, filedir_entry->d_name); if (d_type == DT_UNKNOWN) { - struct stat s; - char path[PATH_MAX]; - snprintf(path, PATH_MAX, "%s/%s", - ctdl_bio_dir, filedir_entry->d_name); if (lstat(path, &s) == 0) { d_type = IFTODT(s.st_mode); } @@ -159,19 +213,15 @@ void cmd_lbio(char *cmdbuf) break; case DT_LNK: case DT_REG: - if (dont_resolve_uids) { - filedir_entry->d_name[d_namelen++] = '\n'; - filedir_entry->d_name[d_namelen] = '\0'; - client_write(filedir_entry->d_name, d_namelen); + usernum = atol(filedir_entry->d_name); + if (CtdlGetUserByNumber(&usbuf, usernum) == 0) { + import_one_bio_file(usbuf.fullname, usernum, path); } - else if (CtdlGetUserByNumber(&usbuf,atol(filedir_entry->d_name))==0) - cprintf("%s\n", usbuf.fullname); } } free(d); closedir(filedir); - cprintf("000\n"); - + rmdir(ctdl_bio_dir); } @@ -180,12 +230,10 @@ CTDL_MODULE_INIT(bio) { if (!threading) { + import_old_bio_files(); CtdlRegisterProtoHook(cmd_ebio, "EBIO", "Enter your bio"); CtdlRegisterProtoHook(cmd_rbio, "RBIO", "Read a user's bio"); - CtdlRegisterProtoHook(cmd_lbio, "LBIO", "List users with bios"); } /* return our module name for the log */ return "bio"; } - - diff --git a/citadel/modules/migrate/serv_migrate.c b/citadel/modules/migrate/serv_migrate.c index 01b71d688..779ff5bed 100644 --- a/citadel/modules/migrate/serv_migrate.c +++ b/citadel/modules/migrate/serv_migrate.c @@ -127,6 +127,8 @@ void migr_export_users_backend(struct ctdluser *buf, void *data) { cprintf("%ld\n", (long)buf->lastcall); cprintf("%d\n", buf->USuserpurge); client_write(HKEY("")); xml_strout(buf->fullname); client_write(HKEY("\n")); + cprintf("%ld\n", buf->msgnum_bio); + cprintf("%ld\n", buf->msgnum_pic); client_write(HKEY("\n")); } @@ -581,10 +583,13 @@ int migr_userrecord(void *data, const char *el) else if (!strcasecmp(el, "u_lastcall")) usbuf.lastcall = atol(ChrPtr(migr_chardata)); else if (!strcasecmp(el, "u_USuserpurge")) usbuf.USuserpurge = atoi(ChrPtr(migr_chardata)); else if (!strcasecmp(el, "u_fullname")) safestrncpy(usbuf.fullname, ChrPtr(migr_chardata), sizeof usbuf.fullname); + else if (!strcasecmp(el, "u_msgnum_bio")) usbuf.msgnum_bio = atol(ChrPtr(migr_chardata)); + else if (!strcasecmp(el, "u_msgnum_pic")) usbuf.msgnum_pic = atol(ChrPtr(migr_chardata)); else return 0; return 1; } + int migr_roomrecord(void *data, const char *el) { if (!strcasecmp(el, "QRname")) safestrncpy(qrbuf.QRname, ChrPtr(migr_chardata), sizeof qrbuf.QRname); @@ -897,7 +902,6 @@ void migr_do_import(void) { */ void migr_do_listdirs(void) { cprintf("%d Don't forget these:\n", LISTING_FOLLOWS); - cprintf("bio|%s\n", ctdl_bio_dir); cprintf("files|%s\n", ctdl_file_dir); cprintf("userpics|%s\n", ctdl_usrpic_dir); cprintf("messages|%s\n", ctdl_message_dir); diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 2709a62fa..466175a8c 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -1,7 +1,7 @@ /* * Implements the message store. * - * Copyright (c) 1987-2015 by the citadel.org team + * Copyright (c) 1987-2016 by the citadel.org team * * This program is open source software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3. @@ -1177,7 +1177,7 @@ struct CtdlMessage *CtdlDeserializeMessage(long msgnum, int with_body, const cha * This is used by CtdlOutputMsg() and other fetch functions. * * NOTE: Caller is responsible for freeing the returned CtdlMessage struct - * using the CtdlMessageFree() function. + * using the CM_Free(); function. */ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body, int run_msg_hooks) { @@ -3063,7 +3063,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* * Convenience function for generating small administrative messages. */ -void quickie_message(const char *from, +long quickie_message(const char *from, const char *fromaddr, const char *to, char *room, @@ -3109,11 +3109,13 @@ void quickie_message(const char *from, CM_SetField(msg, eMesageText, text, strlen(text)); } - CtdlSubmitMsg(msg, recp, room, 0); + long msgnum = CtdlSubmitMsg(msg, recp, room, 0); CM_Free(msg); if (recp != NULL) free_recipients(recp); + return msgnum; } + void flood_protect_quickie_message(const char *from, const char *fromaddr, const char *to, diff --git a/citadel/msgbase.h b/citadel/msgbase.h index 7f9052b76..c19dbbe3d 100644 --- a/citadel/msgbase.h +++ b/citadel/msgbase.h @@ -83,13 +83,7 @@ long send_message (struct CtdlMessage *); void loadtroom (void); long CtdlSubmitMsg(struct CtdlMessage *, recptypes *, const char *, int); -void quickie_message(const char *from, - const char *fromaddr, - const char *to, - char *room, - const char *text, - int format_type, - const char *subject); +long quickie_message(const char *from, const char *fromaddr, const char *to, char *room, const char *text, int format_type, const char *subject); void flood_protect_quickie_message(const char *from, const char *fromaddr, diff --git a/citadel/user_ops.c b/citadel/user_ops.c index 1e8792d71..4e4d99204 100644 --- a/citadel/user_ops.c +++ b/citadel/user_ops.c @@ -1,7 +1,7 @@ /* * Server functions which perform operations on user objects. * - * Copyright (c) 1987-2011 by the citadel.org team + * Copyright (c) 1987-2016 by the citadel.org team * * This program is open source software; you can redistribute it and/or * modify it under the terms of the GNU General Public License, version 3. @@ -1016,14 +1016,6 @@ int purge_user(char pname[]) /* delete the userlog entry */ cdb_delete(CDB_USERS, usernamekey, strlen(usernamekey)); - /* remove the user's bio file */ - snprintf(filename, - sizeof filename, - "%s/%ld", - ctdl_bio_dir, - usbuf.usernum); - unlink(filename); - /* remove the user's picture */ snprintf(filename, sizeof filename, diff --git a/citadel/utillib/citadel_dirs.c b/citadel/utillib/citadel_dirs.c index 1485ac2c5..dc3a85146 100644 --- a/citadel/utillib/citadel_dirs.c +++ b/citadel/utillib/citadel_dirs.c @@ -443,8 +443,6 @@ int create_run_directories(long UID, long GID) int rv; rv = create_dir(ctdl_info_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1); - if (rv != -1) - rv = create_dir(ctdl_bio_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1); if (rv != -1) rv = create_dir(ctdl_usrpic_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1); if (rv != -1) diff --git a/citadel/utils/ctdlmigrate.c b/citadel/utils/ctdlmigrate.c index 18b10f511..d4effa7e1 100644 --- a/citadel/utils/ctdlmigrate.c +++ b/citadel/utils/ctdlmigrate.c @@ -248,11 +248,7 @@ FAIL: if (sourcefp) pclose(sourcefp); while ((fgets(buf, sizeof buf, sourcefp)) && (strcmp(buf, "000"))) { buf[strlen(buf)-1] = 0; - if (!strncasecmp(buf, "bio|", 4)) { - snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/", - socket_path, remote_user, remote_host, &buf[4], ctdl_bio_dir); - } - else if (!strncasecmp(buf, "files|", 6)) { + if (!strncasecmp(buf, "files|", 6)) { snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/", socket_path, remote_user, remote_host, &buf[6], ctdl_file_dir); } -- 2.30.2