main.c - www.codemadness.org - www.codemadness.org saait content files
 (HTM) git clone git://git.codemadness.org/www.codemadness.org
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       main.c (3812B)
       ---
            1 #include <ctype.h>
            2 #include <stdio.h>
            3 #include <stdlib.h>
            4 #include <string.h>
            5 #include <time.h>
            6 
            7 #ifdef __OpenBSD__
            8 #include <unistd.h>
            9 #else
           10 #define pledge(p1,p2) 0
           11 #define unveil(p1,p2) 0
           12 #endif
           13 
           14 int
           15 hexdigit(int c)
           16 {
           17         if (c >= '0' && c <= '9')
           18                 return c - '0';
           19         else if (c >= 'A' && c <= 'F')
           20                 return c - 'A' + 10;
           21         else if (c >= 'a' && c <= 'f')
           22                 return c - 'a' + 10;
           23 
           24         return 0;
           25 }
           26 
           27 /* decode until NUL separator or end of "key". */
           28 int
           29 decodeparam(char *buf, size_t bufsiz, const char *s)
           30 {
           31         size_t i;
           32 
           33         if (!bufsiz)
           34                 return -1;
           35 
           36         for (i = 0; *s && *s != '&'; s++) {
           37                 switch (*s) {
           38                 case '%':
           39                         if (i + 3 >= bufsiz)
           40                                 return -1;
           41                         if (!isxdigit((unsigned char)*(s+1)) ||
           42                             !isxdigit((unsigned char)*(s+2)))
           43                                 return -1;
           44                         buf[i++] = hexdigit(*(s+1)) * 16 + hexdigit(*(s+2));
           45                         s += 2;
           46                         break;
           47                 case '+':
           48                         if (i + 1 >= bufsiz)
           49                                 return -1;
           50                         buf[i++] = ' ';
           51                         break;
           52                 default:
           53                         if (i + 1 >= bufsiz)
           54                                 return -1;
           55                         buf[i++] = *s;
           56                         break;
           57                 }
           58         }
           59         buf[i] = '\0';
           60 
           61         return i;
           62 }
           63 
           64 char *
           65 getparam(const char *query, const char *s)
           66 {
           67         const char *p, *last = NULL;
           68         size_t len;
           69 
           70         len = strlen(s);
           71         for (p = query; (p = strstr(p, s)); p += len) {
           72                 if (p[len] == '=' && (p == query || p[-1] == '&' || p[-1] == '?'))
           73                         last = p + len + 1;
           74         }
           75 
           76         return (char *)last;
           77 }
           78 
           79 void
           80 error(const char *s)
           81 {
           82         fputs("Status: 400 Bad Request\r\n", stdout);
           83         fputs("Content-Type: text/plain\r\n", stdout);
           84         fputs("\r\n", stdout);
           85         fputs(s, stdout);
           86         exit(0);
           87 }
           88 
           89 int
           90 main(void)
           91 {
           92         time_t now;
           93         FILE *fp;
           94         char filename[256];
           95         char _type[32], msg[4096], captcha[16], from[256];
           96         char *p, *query;
           97         int r, valid;
           98 
           99         if (unveil("/donations", "rwc") == -1)
          100                 return 1;
          101         if (pledge("stdio rpath cpath wpath", NULL) == -1)
          102                 return 1;
          103 
          104         query = getenv("QUERY_STRING");
          105         if (!query)
          106                 query = "";
          107         if (query[0] == '?')
          108                 query++;
          109 
          110         valid = 0;
          111         if ((p = getparam(query, "captcha"))) {
          112                 r = decodeparam(captcha, sizeof(captcha), p);
          113                 if (r != -1 && !strcmp(captcha, "yes"))
          114                         valid = 1;
          115         }
          116         if (!valid)
          117                 error("Captcha must be: yes\n");
          118 
          119         from[0] = '\0';
          120         if ((p = getparam(query, "from"))) {
          121                 r = decodeparam(from, sizeof(from), p);
          122                 if (r == -1)
          123                         from[0] = '\0';
          124         }
          125 
          126         valid = 0;
          127         if ((p = getparam(query, "type"))) {
          128                 r = decodeparam(_type, sizeof(_type), p);
          129                 if (r != -1 && (_type[0] == 'c' || _type[0] == 'h' || _type[0] == 'j' || _type[0] == 'm'))
          130                         valid = 1;
          131         }
          132         if (!valid)
          133                 error("Please select a type of donation\n");
          134 
          135         valid = 0;
          136         if ((p = getparam(query, "msg"))) {
          137                 r = decodeparam(msg, sizeof(msg), p);
          138                 if (msg[0])
          139                         valid = 1;
          140         }
          141         if (!valid)
          142                 error("Please type a message\n");
          143 
          144         if (!(p = getparam(query, "pay")))
          145                 error("Please click the pay button\n");
          146 
          147         /* future scaling improvement: multiple parallel donations at the same time won't work */
          148         now = time(NULL);
          149         r = snprintf(filename, sizeof(filename), "/donations/%c_%lld.txt", _type[0], (long long)now);
          150         if (r < 0 || (size_t)r >= sizeof(filename))
          151                 error("shit happens\n");
          152 
          153         fp = fopen(filename, "w+b");
          154         if (!fp)
          155                 error("Cannot receive donation, thanks anyway.\n");
          156 
          157         if (from[0])
          158                 fputs(from, fp);
          159         else
          160                 fputs("Some person", fp);
          161 
          162         switch (_type[0]) {
          163         case 'c':
          164                 fputs(" sent a compliment:\n\n", fp);
          165                 break;
          166         case 'h':
          167                 fputs(" sent pure hatred:\n\n", fp);
          168                 break;
          169         case 'j':
          170                 fputs(" sent a joke:\n\n", fp);
          171                 break;
          172         case 'm':
          173                 fputs(" sent ONE MILLION DOLLARS:\n\n", fp);
          174                 break;
          175         }
          176 
          177         fputs(msg, fp);
          178         fputs("\n", fp);
          179         fclose(fp);
          180 
          181         if (_type[0] == 'm') {
          182                 fputs("Status: 302 Found\r\n", stdout);
          183 
          184                 fputs("Location: https://www.codemadness.org/downloads/1_million_dollars.webm\r\n", stdout);
          185         } else {
          186                 fputs("Status: 200 OK\r\n", stdout);
          187         }
          188 
          189         fputs("Content-Type: text/plain\r\n", stdout);
          190         fputs("\r\n", stdout);
          191         fputs("Thank you for your donation!\n", stdout);
          192         return 0;
          193 
          194         return 0;
          195 }