/************************************************************************************************* * CGI script for file uploader * Copyright (C) 2000-2003 Mikio Hirabayashi * This file is part of QDBM, Quick Database Manager. * QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU * Lesser General Public License as published by the Free Software Foundation; either version * 2.1 of the License or any later version. QDBM is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * You should have received a copy of the GNU Lesser General Public License along with QDBM; if * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA. *************************************************************************************************/ #include #include #include #include #include #include #include #include #undef TRUE #define TRUE 1 /* boolean true */ #undef FALSE #define FALSE 0 /* boolean false */ #define CONFFILE "qupl.conf" /* name of the configuration file */ #define DEFENC "US-ASCII" /* default encoding */ #define DEFLANG "en" /* default language */ #define DEFTITLE "File Uploader" /* default title */ #define DEFDATADIR "qupldir" /* directory containing files */ /* global variables */ const char *scriptname; /* name of the script */ const char *enc; /* encoding of the page */ const char *lang; /* language of the page */ const char *title; /* title of the page */ int quota; /* limit of the total size */ /* function prototypes */ int main(int argc, char **argv); const char *skiplabel(const char *str); void htmlprintf(const char *format, ...); int getdirsize(const char *path); const char *datestr(time_t t); const char *gettype(const char *path); /* main routine */ int main(int argc, char **argv){ CBLIST *lines, *parts, *files; CBMAP *params; FILE *ifp; const char *tmp, *datadir, *body, *sname; char *wp, *bound, *cdata, *filedata, *filename, *ebuf, *dbuf, *getname, *delname, numbuf[32]; int i, clen, blen, filesize, c, sdir, ssize, total; time_t stime; /* set configurations */ cbstdiobin(); scriptname = argv[0]; if((tmp = getenv("SCRIPT_NAME")) != NULL) scriptname = tmp; enc = NULL; lang = NULL; title = NULL; datadir = NULL; quota = 0; if((lines = cbreadlines(CONFFILE)) != NULL){ for(i = 0; i < cblistnum(lines); i++){ tmp = cblistval(lines, i, NULL); if(cbstrfwmatch(tmp, "encoding:")){ enc = skiplabel(tmp); } else if(cbstrfwmatch(tmp, "lang:")){ lang = skiplabel(tmp); } else if(cbstrfwmatch(tmp, "title:")){ title = skiplabel(tmp); } else if(cbstrfwmatch(tmp, "datadir:")){ datadir = skiplabel(tmp); } else if(cbstrfwmatch(tmp, "quota:")){ quota = atoi(skiplabel(tmp)); } } } if(!enc) enc = DEFENC; if(!lang) lang = DEFLANG; if(!title) title = DEFTITLE; if(!datadir) datadir = DEFDATADIR; if(quota < 0) quota = 0; /* read parameters */ filedata = NULL; filesize = 0; filename = NULL; getname = NULL; delname = NULL; if((tmp = getenv("REQUEST_METHOD")) != NULL && !strcmp(tmp, "POST") && (tmp = getenv("CONTENT_LENGTH")) != NULL && (clen = atoi(tmp)) > 0 && (tmp = getenv("CONTENT_TYPE")) != NULL && cbstrfwmatch(tmp, "multipart/form-data") && (tmp = strstr(tmp, "boundary=")) != NULL){ tmp += 9; if(*tmp == '"') tmp++; bound = cbmemdup(tmp, -1); if((wp = strchr(bound, ';')) != NULL) *wp = '\0'; cdata = cbmalloc(clen + 1); for(i = 0; i < clen && (c = getchar()) != EOF; i++){ cdata[i] = c; } parts = cbmimeparts(cdata, clen, bound); if(cblistnum(parts) > 0){ body = cblistval(parts, 0, &blen); params = cbmapopen(); filedata = cbmimebreak(body, blen, params, &filesize); if((tmp = cbmapget(params, "FILENAME", -1, NULL)) != NULL) filename = cbmemdup(tmp, -1); cbmapclose(params); } cblistclose(parts); free(cdata); free(bound); } else if((tmp = getenv("PATH_INFO")) != NULL){ if(tmp[0] == '/') tmp++; getname = cburldecode(tmp, NULL); if(cbstrfwmatch(getname, "../") || strstr(getname, "/../") != NULL){ free(getname); getname = NULL; } } else if((tmp = getenv("QUERY_STRING")) != NULL && (tmp = strstr(tmp, "delfile="))){ tmp += 8; delname = cburldecode(tmp, NULL); if(cbstrfwmatch(delname, "../") || strstr(delname, "/../") != NULL){ free(delname); delname = NULL; } } if(getname){ /* send data of the file */ if(chdir(datadir) == 0 && (ifp = fopen(getname, "rb")) != NULL){ printf("Content-Type: %s\r\n", gettype(getname)); printf("Cache-Control: no-cache, must-revalidate\r\n"); printf("Pragma: no-cache\r\n"); printf("\r\n"); while((c = fgetc(ifp)) != EOF){ putchar(c); } fclose(ifp); } else { printf("Status: 404 Not Found\r\n"); printf("Content-Type: text/plain; charset=%s\r\n", enc); printf("Cache-Control: no-cache, must-revalidate\r\n"); printf("Pragma: no-cache\r\n"); printf("\r\n"); printf("Not Found\n"); printf("%s\n", getname); } } else { /* output headers */ printf("Content-Type: text/html; charset=%s\r\n", enc); printf("Cache-Control: no-cache, must-revalidate\r\n"); printf("Pragma: no-cache\r\n"); printf("\r\n"); htmlprintf("\n", enc); htmlprintf("\n"); htmlprintf("\n", lang, lang); htmlprintf("\n"); htmlprintf("\n", enc); htmlprintf("\n"); htmlprintf("\n"); htmlprintf("%@\n", title); htmlprintf("\n"); htmlprintf("\n"); htmlprintf("\n"); htmlprintf("

%@

\n", title); htmlprintf("
\n"); htmlprintf("
\n", scriptname); htmlprintf("
\n"); htmlprintf("\n"); htmlprintf("\n"); htmlprintf("[RELOAD]\n", scriptname); htmlprintf("
\n"); htmlprintf("
\n"); htmlprintf("
\n"); /* change the currnt directory */ if(chdir(datadir) == -1){ htmlprintf("

Changing the current directory was failed.

\n"); htmlprintf("
\n"); } else { /* save the file */ if(filedata && filename){ sname = filename; if((ebuf = cbiconv(filename, -1, enc, "UTF-8", NULL, NULL)) != NULL) sname = ebuf; if((tmp = strrchr(sname, '/')) != NULL) sname = tmp + 1; if((tmp = strrchr(sname, '\\')) != NULL) sname = tmp + 1; if(ebuf){ while((tmp = strstr(sname, "\xc2\xa5")) != NULL){ sname = tmp + 2; } } dbuf = NULL; if(ebuf && (dbuf = cbiconv(sname, -1, "UTF-8", enc, NULL, NULL)) != NULL) sname = dbuf; if(getdirsize(".") + filesize > quota){ htmlprintf("

Exceeding the quota. -- %@

\n", sname); } else if(!cbwritefile(sname, filedata, filesize)){ htmlprintf("

Uploading was failed. -- %@

\n", sname); } else { htmlprintf("

Uploading was succeeded. -- %@

\n", sname); } htmlprintf("
\n"); free(dbuf); free(ebuf); } else if(delname){ /* delete the file */ if(unlink(delname) == 0){ htmlprintf("

Deleting was succeeded. -- %@

\n", delname); } else { htmlprintf("

Deleting was failed. -- %@

\n", delname); } htmlprintf("
\n"); } /* show the file list */ if((files = cbdirlist(".")) != NULL){ cblistsort(files); htmlprintf("\n"); htmlprintf("\n"); htmlprintf("\n"); htmlprintf("\n"); htmlprintf("\n"); htmlprintf("\n"); htmlprintf("\n"); for(i = 0; i < cblistnum(files); i++){ sname = cblistval(files, i, NULL); if(!strcmp(sname, ".") || !strcmp(sname, "..")) continue; if(!cbfilestat(sname, &sdir, &ssize, &stime) || sdir) continue; htmlprintf("\n"); htmlprintf("\n", sname); htmlprintf("\n", ssize); htmlprintf("\n", datestr(stime)); htmlprintf("\n"); htmlprintf("\n"); } htmlprintf("
NameSizeModified TimeActions
%@%d%@\n"); htmlprintf("[GET]", scriptname, sname); htmlprintf(" / "); htmlprintf("[DEL]", scriptname, sname); htmlprintf("
\n"); cblistclose(files); total = getdirsize("."); sprintf(numbuf, "%.2f%%", (total * 100.0) / quota); htmlprintf("
Capacity: %@ (%d/%d)
\n", numbuf, total, quota); } else { htmlprintf("

Listing files in the data directory was failed.

\n"); } htmlprintf("
\n"); } /* output footers */ htmlprintf("
Powered by QDBM %@.
\n", dpversion); htmlprintf("\n"); htmlprintf("\n"); } /* release resources */ if(getname) free(getname); if(delname) free(delname); if(filename) free(filename); if(filedata) free(filedata); if(lines) cblistclose(lines); return 0; } /* skip the label of a line */ const char *skiplabel(const char *str){ if(!(str = strchr(str, ':'))) return str; str++; while(*str != '\0' && (*str == ' ' || *str == '\t')){ str++; } return str; } /* HTML-oriented printf */ void htmlprintf(const char *format, ...){ va_list ap; char *tmp; unsigned char c; va_start(ap, format); while(*format != '\0'){ if(*format == '%'){ format++; switch(*format){ case 's': tmp = va_arg(ap, char *); if(!tmp) tmp = "(null)"; printf("%s", tmp); break; case 'd': printf("%d", va_arg(ap, int)); break; case '@': tmp = va_arg(ap, char *); if(!tmp) tmp = "(null)"; while(*tmp){ switch(*tmp){ case '&': printf("&"); break; case '<': printf("<"); break; case '>': printf(">"); break; case '"': printf("""); break; default: putchar(*tmp); break; } tmp++; } break; case '?': tmp = va_arg(ap, char *); if(!tmp) tmp = "(null)"; while(*tmp){ c = *(unsigned char *)tmp; if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c != '\0' && strchr("_-.", c))){ putchar(c); } else if(c == ' '){ putchar('+'); } else { printf("%%%02X", c); } tmp++; } break; case '%': putchar('%'); break; } } else { putchar(*format); } format++; } va_end(ap); } /* get the total size of files in a directory */ int getdirsize(const char *path){ CBLIST *files; const char *sname; int i, total, isdir, size; total = 0; if((files = cbdirlist(path)) != NULL){ for(i = 0; i < cblistnum(files); i++){ sname = cblistval(files, i, NULL); if(!strcmp(sname, ".") || !strcmp(sname, "..")) continue; if(!cbfilestat(sname, &isdir, &size, NULL) || isdir) continue; total += size; } } return total; } /* get static string of the date */ const char *datestr(time_t t){ static char buf[32]; struct tm *stp; if(!(stp = localtime(&t))) return "0000/00/00 00:00:00"; sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d", stp->tm_year + 1900, stp->tm_mon + 1, stp->tm_mday, stp->tm_hour, stp->tm_min, stp->tm_sec); return buf; } /* get the media type of a file */ const char *gettype(const char *path){ char *types[] = { ".txt", "text/plain", ".asc", "text/plain", ".html", "text/html", ".htm", "text/html", ".mht", "message/rfc822", ".sgml", "application/sgml", ".sgm", "application/sgml", ".xml", "application/xml", ".rtf", "application/rtf", ".pdf", "application/pdf", ".doc", "application/msword", ".xls", "application/vnd.ms-excel", ".ppt", "application/vnd.ms-powerpoint", ".xdw", "application/vnd.fujixerox.docuworks", ".zip", "application/zip", ".tar", "application/x-tar", ".gz", "application/x-gzip", ".png", "image/png", ".gif", "image/gif", ".jpg", "image/jpeg", ".jpeg", "image/jpeg", ".tif", "image/tiff", ".tiff", "image/tiff", ".bmp", "image/bmp", ".mid", "audio/midi", ".midi", "audio/midi", ".mp3", "audio/mpeg", ".wav", "audio/x-wav", ".mpg", "video/mpeg", ".mpeg", "video/mpeg", NULL }; int i; for(i = 0; types[i]; i += 2){ if(cbstrbwimatch(path, types[i])) return types[i+1]; } return "application/octet-stream"; } /* END OF FILE */