"Fossies" - the Fresh Open Source Software Archive

Member "citadel/modules/image/serv_image.c" (5 Jun 2021, 10930 Bytes) of package /linux/www/citadel.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "serv_image.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (c) 1987-2021 by the citadel.org team
    3  *
    4  * This program is open source software; you can redistribute it and/or modify
    5  * it under the terms of the GNU General Public License as published by
    6  * the Free Software Foundation; either version 3 of the License, or
    7  * (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  */
   14 
   15 #include "ctdl_module.h"
   16 #include "config.h"
   17 #include <sys/types.h>
   18 #include <sys/stat.h>
   19 #include <dirent.h>
   20 
   21 
   22 /*
   23  * DownLoad Room Image (see its icon or whatever)
   24  * If this command succeeds, it follows the same protocol as the DLAT command.
   25  */
   26 void cmd_dlri(char *cmdbuf) {
   27     if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
   28     if (CC->room.msgnum_pic < 1) {
   29         cprintf("%d No image found.\n", ERROR + FILE_NOT_FOUND);
   30         return;
   31     }
   32 
   33     struct CtdlMessage *msg = CtdlFetchMessage(CC->room.msgnum_pic, 1);
   34     if (msg != NULL) {
   35         // The call to CtdlOutputPreLoadedMsg() with MT_SPEW_SECTION will cause the DLRI command
   36         // to have the same output format as the DLAT command, because it calls the same code.
   37         // For example: 600 402132|-1||image/gif|
   38         safestrncpy(CC->download_desired_section, "1", sizeof CC->download_desired_section);
   39         CtdlOutputPreLoadedMsg(msg, MT_SPEW_SECTION, HEADERS_NONE, 1, 0, 0);
   40         CM_Free(msg);
   41     }
   42     else {
   43         cprintf("%d No image found.\n", ERROR + MESSAGE_NOT_FOUND);
   44         return;
   45     }
   46 }
   47 
   48 
   49 /*
   50  * UpLoad Room Image (avatar or photo or whatever)
   51  */
   52 void cmd_ulri(char *cmdbuf) {
   53     long data_length;
   54     char mimetype[SIZ];
   55 
   56     if (CtdlAccessCheck(ac_room_aide)) return;
   57 
   58     data_length = extract_long(cmdbuf, 0);
   59     extract_token(mimetype, cmdbuf, 1, '|', sizeof mimetype);
   60 
   61     if (data_length < 20) {
   62         cprintf("%d That's an awfully small file.  Try again.\n", ERROR + ILLEGAL_VALUE);
   63         return;
   64     }
   65 
   66     if (strncasecmp(mimetype, "image/", 6)) {
   67         cprintf("%d Only image files are permitted.\n", ERROR + ILLEGAL_VALUE);
   68         return;
   69     }
   70 
   71     char *unencoded_data = malloc(data_length + 1);
   72     if (!unencoded_data) {
   73         cprintf("%d Could not allocate %ld bytes of memory\n", ERROR + INTERNAL_ERROR , data_length);
   74         return;
   75     }
   76 
   77     cprintf("%d %ld\n", SEND_BINARY, data_length);
   78     client_read(unencoded_data, data_length);
   79 
   80     // We've got the data read from the client, now save it.
   81     char *encoded_data = malloc((data_length * 2) + 100);
   82     if (encoded_data) {
   83         sprintf(encoded_data, "Content-type: %s\nContent-transfer-encoding: base64\n\n", mimetype);
   84         CtdlEncodeBase64(&encoded_data[strlen(encoded_data)], unencoded_data, data_length, 1);
   85         long new_msgnum = quickie_message("Citadel", NULL, NULL, SYSCONFIGROOM, encoded_data, FMT_RFC822, "Image uploaded by admin user");
   86 
   87         if (CtdlGetRoomLock(&CC->room, CC->room.QRname) == 0) {
   88             long old_msgnum = CC->room.msgnum_pic;
   89             syslog(LOG_DEBUG, "Message %ld is now the photo for %s", new_msgnum, CC->room.QRname);
   90             CC->room.msgnum_pic = new_msgnum;
   91             CtdlPutRoomLock(&CC->room);
   92             if (old_msgnum > 0) {
   93                 syslog(LOG_DEBUG, "Deleting old message %ld from %s", old_msgnum, SYSCONFIGROOM);
   94                 CtdlDeleteMessages(SYSCONFIGROOM, &old_msgnum, 1, "");
   95             }
   96         }
   97         free(encoded_data);
   98     }
   99 
  100     free(unencoded_data);
  101 }
  102 
  103 
  104 /*
  105  * DownLoad User Image (see their avatar or photo or whatever)
  106  * If this command succeeds, it follows the same protocol as the DLAT command.
  107  */
  108 void cmd_dlui(char *cmdbuf) {
  109     struct ctdluser ruser;
  110     char buf[SIZ];
  111 
  112     if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
  113     extract_token(buf, cmdbuf, 0, '|', sizeof buf);
  114     if (CtdlGetUser(&ruser, buf) != 0) {
  115         cprintf("%d No such user.\n", ERROR + NO_SUCH_USER);
  116         return;
  117     }
  118     if (ruser.msgnum_pic < 1) {
  119         cprintf("%d No image found.\n", ERROR + FILE_NOT_FOUND);
  120         return;
  121     }
  122 
  123     struct CtdlMessage *msg = CtdlFetchMessage(ruser.msgnum_pic, 1);
  124     if (msg != NULL) {
  125         // The call to CtdlOutputPreLoadedMsg() with MT_SPEW_SECTION will cause the DLUI command
  126         // to have the same output format as the DLAT command, because it calls the same code.
  127         // For example: 600 402132|-1||image/gif|
  128         safestrncpy(CC->download_desired_section, "1", sizeof CC->download_desired_section);
  129         CtdlOutputPreLoadedMsg(msg, MT_SPEW_SECTION, HEADERS_NONE, 1, 0, 0);
  130         CM_Free(msg);
  131     }
  132     else {
  133         cprintf("%d No image found.\n", ERROR + MESSAGE_NOT_FOUND);
  134         return;
  135     }
  136 }
  137 
  138 
  139 /*
  140  * UpLoad User Image (avatar or photo or whatever)
  141  */
  142 void cmd_ului(char *cmdbuf) {
  143     long data_length;
  144     char mimetype[SIZ];
  145     char username[USERNAME_SIZE];
  146     char userconfigroomname[ROOMNAMELEN];
  147 
  148     if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
  149 
  150     if (num_parms(cmdbuf) < 2) {
  151         cprintf("%d Usage error\n", ERROR + ILLEGAL_VALUE);
  152         return;
  153     }
  154 
  155     data_length = extract_long(cmdbuf, 0);
  156     extract_token(mimetype, cmdbuf, 1, '|', sizeof mimetype);
  157     extract_token(username, cmdbuf, 2, '|', sizeof username);
  158 
  159     if (data_length < 20) {
  160         cprintf("%d That's an awfully small file.  Try again.\n", ERROR + ILLEGAL_VALUE);
  161         return;
  162     }
  163 
  164     if (strncasecmp(mimetype, "image/", 6)) {
  165         cprintf("%d Only image files are permitted.\n", ERROR + ILLEGAL_VALUE);
  166         return;
  167     }
  168 
  169     if (IsEmptyStr(username)) {
  170         safestrncpy(username, CC->curr_user, sizeof username);
  171     }
  172 
  173     // Normal users can only change their own photo
  174     if ( (strcasecmp(username, CC->curr_user)) && (CC->user.axlevel < AxAideU) && (!CC->internal_pgm) ) {
  175         cprintf("%d Higher access required to change another user's photo.\n", ERROR + HIGHER_ACCESS_REQUIRED);
  176     }
  177 
  178     // Check to make sure the user exists
  179     struct ctdluser usbuf;
  180     if (CtdlGetUser(&usbuf, username) != 0) {       // check for existing user, don't lock it yet
  181         cprintf("%d %s not found.\n", ERROR + NO_SUCH_USER , username);
  182         return;
  183     }
  184     CtdlMailboxName(userconfigroomname, sizeof userconfigroomname, &usbuf, USERCONFIGROOM);
  185 
  186     char *unencoded_data = malloc(data_length + 1);
  187     if (!unencoded_data) {
  188         cprintf("%d Could not allocate %ld bytes of memory\n", ERROR + INTERNAL_ERROR , data_length);
  189         return;
  190     }
  191 
  192     cprintf("%d %ld\n", SEND_BINARY, data_length);
  193     client_read(unencoded_data, data_length);
  194 
  195     // We've got the data read from the client, now save it.
  196     char *encoded_data = malloc((data_length * 2) + 100);
  197     if (encoded_data) {
  198         sprintf(encoded_data, "Content-type: %s\nContent-transfer-encoding: base64\n\n", mimetype);
  199         CtdlEncodeBase64(&encoded_data[strlen(encoded_data)], unencoded_data, data_length, 1);
  200         long new_msgnum = quickie_message("Citadel", NULL, NULL, userconfigroomname, encoded_data, FMT_RFC822, "Photo uploaded by user");
  201 
  202         if (CtdlGetUserLock(&usbuf, username) == 0) {   // lock it this time
  203             long old_msgnum = usbuf.msgnum_pic;
  204             syslog(LOG_DEBUG, "Message %ld is now the photo for %s", new_msgnum, username);
  205             usbuf.msgnum_pic = new_msgnum;
  206             CtdlPutUserLock(&usbuf);
  207             if (old_msgnum > 0) {
  208                 syslog(LOG_DEBUG, "Deleting old message %ld from %s", old_msgnum, userconfigroomname);
  209                 CtdlDeleteMessages(userconfigroomname, &old_msgnum, 1, "");
  210             }
  211         }
  212 
  213         free(encoded_data);
  214     }
  215 
  216     free(unencoded_data);
  217 }
  218 
  219 
  220 /*
  221  * Import function called by import_old_userpic_files() for a single user
  222  */
  223 void import_one_userpic_file(char *username, long usernum, char *path) {
  224     syslog(LOG_DEBUG, "Import legacy userpic for %s, usernum=%ld, filename=%s", username, usernum, path);
  225 
  226     FILE *fp = fopen(path, "r");
  227     if (!fp) return;
  228 
  229     fseek(fp, 0, SEEK_END);
  230     long data_length = ftell(fp);
  231 
  232     if (data_length >= 1) {
  233         rewind(fp);
  234         char *unencoded_data = malloc(data_length);
  235         if (unencoded_data) {
  236             fread(unencoded_data, data_length, 1, fp);
  237             char *encoded_data = malloc((data_length * 2) + 100);
  238             if (encoded_data) {
  239                 sprintf(encoded_data, "Content-type: %s\nContent-transfer-encoding: base64\n\n", GuessMimeByFilename(path, strlen(path)));
  240                 CtdlEncodeBase64(&encoded_data[strlen(encoded_data)], unencoded_data, data_length, 1);
  241 
  242                 char userconfigroomname[ROOMNAMELEN];
  243                 struct ctdluser usbuf;
  244 
  245                 if (CtdlGetUser(&usbuf, username) == 0) {   // no need to lock it , we are still initializing
  246                     long old_msgnum = usbuf.msgnum_pic;
  247                     CtdlMailboxName(userconfigroomname, sizeof userconfigroomname, &usbuf, USERCONFIGROOM);
  248                     long new_msgnum = quickie_message("Citadel", NULL, NULL, userconfigroomname, encoded_data, FMT_RFC822, "Photo imported from file");
  249                     syslog(LOG_DEBUG, "Message %ld is now the photo for %s", new_msgnum, username);
  250                     usbuf.msgnum_pic = new_msgnum;
  251                     CtdlPutUser(&usbuf);
  252                     unlink(path);               // delete the old file , it's in the database now
  253                     if (old_msgnum > 0) {
  254                         syslog(LOG_DEBUG, "Deleting old message %ld from %s", old_msgnum, userconfigroomname);
  255                         CtdlDeleteMessages(userconfigroomname, &old_msgnum, 1, "");
  256                     }
  257                 }
  258                 free(encoded_data);
  259             }
  260             free(unencoded_data);
  261         }
  262     }
  263     fclose(fp);
  264 }
  265 
  266 
  267 /*
  268  * Look for old-format "userpic" files and import them into the message base
  269  */
  270 void import_old_userpic_files(void) {
  271     DIR *filedir = NULL;
  272     struct dirent *filedir_entry;
  273     size_t d_namelen;
  274     struct ctdluser usbuf;
  275     long usernum = 0;
  276     int d_type = 0;
  277     struct stat s;
  278     char path[PATH_MAX];
  279 
  280 
  281     syslog(LOG_DEBUG, "Importing old style userpic files into the message base");
  282     filedir = opendir (ctdl_usrpic_dir);
  283     if (filedir == NULL) {
  284         return;
  285     }
  286     while ( (filedir_entry = readdir(filedir)) , (filedir_entry != NULL))
  287     {
  288 #ifdef _DIRENT_HAVE_D_NAMLEN
  289         d_namelen = filedir_entry->d_namlen;
  290 
  291 #else
  292         d_namelen = strlen(filedir_entry->d_name);
  293 #endif
  294 
  295 #ifdef _DIRENT_HAVE_D_TYPE
  296         d_type = filedir_entry->d_type;
  297 #else
  298 
  299 #ifndef DT_UNKNOWN
  300 #define DT_UNKNOWN     0
  301 #define DT_DIR         4
  302 #define DT_REG         8
  303 #define DT_LNK         10
  304 
  305 #define IFTODT(mode)   (((mode) & 0170000) >> 12)
  306 #define DTTOIF(dirtype)        ((dirtype) << 12)
  307 #endif
  308         d_type = DT_UNKNOWN;
  309 #endif
  310         if ((d_namelen == 1) && 
  311             (filedir_entry->d_name[0] == '.'))
  312             continue;
  313 
  314         if ((d_namelen == 2) && 
  315             (filedir_entry->d_name[0] == '.') &&
  316             (filedir_entry->d_name[1] == '.'))
  317             continue;
  318 
  319         snprintf(path, PATH_MAX, "%s/%s", ctdl_usrpic_dir, filedir_entry->d_name);
  320         if (d_type == DT_UNKNOWN) {
  321             if (lstat(path, &s) == 0) {
  322                 d_type = IFTODT(s.st_mode);
  323             }
  324         }
  325         switch (d_type)
  326         {
  327         case DT_DIR:
  328             break;
  329         case DT_LNK:
  330         case DT_REG:
  331             usernum = atol(filedir_entry->d_name);
  332             if (CtdlGetUserByNumber(&usbuf, usernum) == 0) {
  333                 import_one_userpic_file(usbuf.fullname, usernum, path);
  334             }
  335         }
  336     }
  337     closedir(filedir);
  338     rmdir(ctdl_usrpic_dir);
  339 }
  340 
  341 
  342 
  343 CTDL_MODULE_INIT(image)
  344 {
  345     if (!threading)
  346     {
  347         import_old_userpic_files();
  348             CtdlRegisterProtoHook(cmd_dlri, "DLRI", "DownLoad Room Image");
  349             CtdlRegisterProtoHook(cmd_ulri, "ULRI", "UpLoad Room Image");
  350             CtdlRegisterProtoHook(cmd_dlui, "DLUI", "DownLoad User Image");
  351             CtdlRegisterProtoHook(cmd_ului, "ULUI", "UpLoad User Image");
  352     }
  353     /* return our module name for the log */
  354         return "image";
  355 }