diff --git a/derby/derby.mk b/derby/derby.mk index 00a2c20..423692e 100644 --- a/derby/derby.mk +++ b/derby/derby.mk @@ -1 +1,5 @@ -PLAIN += $(wildcard derby/*.mdwn) +PLAIN += derby +COPY += derby/scrimmage.pdf + +$(DESTDIR)/derby/scrimmage.pdf: derby/scrimmage.ps + ps2pdf $< $@ diff --git a/derby/index.mdwn b/derby/index.mdwn index f9dde5c..55685ef 100644 --- a/derby/index.mdwn +++ b/derby/index.mdwn @@ -13,9 +13,9 @@ The Woozle Promise Software -------- -* [Scoreboard](/scoreboard/), works in any web browser -* [Penalty Timer (Android)](https://play.google.com/store/apps/details?id=org.woozle.penaltytimer) -* [Track](/track/) with movable players +* [Scoreboard](/scoreboard/), works in any web browser -- [source](http://woozle.org/~neale/g.cgi/scoreboard/) +* [Penalty Timer for Android](https://play.google.com/store/apps/details?id=org.woozle.penaltytimer) -- [source](http://woozle.org/~neale/g.cgi/ptimer/) +* [Track](/track/) with movable players -- [source](http://woozle.org/~neale/g.cgi/track/) Forms ----- diff --git a/ilohamail.cgi.c b/ilohamail.cgi.c new file mode 100644 index 0000000..3c7924f --- /dev/null +++ b/ilohamail.cgi.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +const char *basepath = "/usr/share/IlohaMail/source"; + +int +main(int argc, char *argv[]) +{ + char *pathinfo = getenv("PATH_INFO"); + char filename[512]; + + if ((! pathinfo) || + (! strcmp(pathinfo, "/")) || + (0 == strcmp(pathinfo, "/index.html"))) { + pathinfo = "/index.php"; + } + snprintf(filename, sizeof filename, "%s%s", basepath, pathinfo); + setenv("SCRIPT_FILENAME", filename, 1); + setenv("REDIRECT_STATUS", "fuck me", 1); + execl("/usr/bin/php-cgi", filename, NULL); + + return 0; +} diff --git a/index.mdwn b/index.mdwn index c8d3db6..9a2a0ff 100644 --- a/index.mdwn +++ b/index.mdwn @@ -7,3 +7,63 @@ held by folks who know the right person to ask. + +December 8 pt. 2: Webmail works now +----------------------------------- + +I didn't get a chance to test webmail before I had to run off to an appointment. +It's back up now, near as I can tell. + + +December 8: SSL Certificate Renewed +----------------------------------- + +Woozle now has a new SSL certificate, +thanks to the generous folks at [StartCom](http://www.startssl.com). +I think everything is back to normal. + +If you are having trouble with web, or sending or recieving email, +please *please* let me (Neale) know right away. +Phone or text message is okay. +As far as I can tell, everything's working fine, +and I depend on *you* to tell me otherwise. + + + + +December 7: Expired SSL Certificate +----------------------------------- + +Woozle's SSL certificate expired tonight. It's my own fault: I +thought the warnings were spam. + +I'll have a new SSL certificate in place hopefully before Monday. +In the meantime, you will either have to tell your mail client that it's okay to use the expired certificate, +or if you're not comfortable with that +(I wouldn't blame you), +wait until I can get it fixed. + +I hope to have a new certificate installed by Monday, +but I have to wait for a lot of bureaucracy to churn through my +application so I don't know when, exactly, I will be able +to install a new certificate. +The SSL certificate is one of the few things about woozle that I have little control over. +It also costs me more to buy the certificate than it does to run the entire rest of the machine. + +My apologies. + + +October 9: New Webmail +---------------------- + +The October 2 change broke webmail. Again. Rather than fix it again, +I thought everyone would enjoy a more modern webmail client. You can +still get to [the old one](https://woozle.org/ilohamail.cgi) if you +want to pull your address book out or something, but I'm planning on +removing it in a few months unless someone asks me not to. + +Mail filtering is now available. You can +get to that under Settings. This uses a standard filtering language, +so your filters will stick around if I have to change the webmail +program again. These filters also apply to IMAP clients (like your +Android or iPhone, or Thunderbird). diff --git a/l.cgi.c b/l.cgi.c new file mode 100644 index 0000000..05ffc88 --- /dev/null +++ b/l.cgi.c @@ -0,0 +1,376 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char *BASE_DIR = "/tmp/clicko"; +const char *BASE_URL = "http://woozle.org/l.cgi"; + + +#define POST_MAX 1024 + +/* + * CGI + */ +static int is_cgi = 0; +static char **argv = NULL; + +static int +read_char_argv() +{ + static int arg = 0; + static char *p; + + if (NULL == argv) { + return EOF; + } + + if (0 == arg) { + arg = 1; + p = argv[1]; + } + + if (! p) { + return EOF; + } else if (! *p) { + arg += 1; + p = argv[arg]; + return '&'; + } + + return *(p++); +} + +static int +read_char_stdin() +{ + static int inlen = -1; + + if (-1 == inlen) { + char *p = getenv("CONTENT_LENGTH"); + if (p) { + inlen = atoi(p); + if (inlen > POST_MAX) { + inlen = POST_MAX; + } + if (inlen < 0) { + inlen = 0; + } + } else { + inlen = 0; + } + } + + if (inlen) { + inlen -= 1; + return getchar(); + } + return EOF; +} + +static int +read_char_query_string() +{ + static char *p = (char *)-1; + + if ((char *)-1 == p) { + p = getenv("QUERY_STRING"); + } + + if (! p) { + return EOF; + } else if (! *p) { + return EOF; + } else { + return *(p++); + } +} + +static int (* read_char)() = read_char_argv; + +int +cgi_init(char *global_argv[]) +{ + char *rm = getenv("REQUEST_METHOD"); + + if (! rm) { + read_char = read_char_argv; + argv = global_argv; + } else if (0 == strcmp(rm, "POST")) { + read_char = read_char_stdin; + is_cgi = 1; + } else if (0 == strcmp(rm, "GET")) { + read_char = read_char_query_string; + is_cgi = 1; + } else { + printf(("405 Method not allowed\r\n" + "Allow: GET, POST\r\n" + "Content-type: text/plain\r\n" + "\r\n" + "%s is not allowed.\n"), + rm); + return -1; + } + + return 0; +} + +static char +tonum(int c) +{ + if ((c >= '0') && (c <= '9')) { + return c - '0'; + } + if ((c >= 'a') && (c <= 'f')) { + return 10 + c - 'a'; + } + if ((c >= 'A') && (c <= 'F')) { + return 10 + c - 'A'; + } + return 0; +} + +static char +read_hex() +{ + int a = read_char(); + int b = read_char(); + + return tonum(a)*16 + tonum(b); +} + +/* Read a key or a value. Since & and = aren't supposed to appear + outside of boundaries, we can use the same function for both. +*/ +size_t +cgi_item(char *str, size_t maxlen) +{ + int c; + size_t pos = 0; + + while (1) { + c = read_char(); + switch (c) { + case EOF: + case '=': + case '&': + str[pos] = '\0'; + return pos; + case '%': + c = read_hex(); + break; + case '+': + c = ' '; + break; + } + if (pos < maxlen - 1) { + str[pos] = c; + pos += 1; + } + } +} + +void +cgi_head(char *title) +{ + if (is_cgi) { + printf("Content-type: text/html\r\n\r\n"); + } + printf(("\n" + "\n" + " %s\n" + " \n" + "

%s

\n"), + title, title); +} + +void +cgi_foot() +{ + printf("\n" + " \n" + "\n"); +} + +void +cgi_result(int code, char *desc, char *fmt, ...) +{ + va_list ap; + + if (is_cgi) { + printf("%d %s\r\n", code, desc); + } + cgi_head(desc); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + cgi_foot(); + exit(0); +} + +void +cgi_page(char *title, char *fmt, ...) +{ + va_list ap; + + cgi_head(title); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + cgi_foot(); + exit(0); +} + +void +cgi_error(char *text) +{ + cgi_result(500, "Internal error", "

%s

", text); +} + + +static FILE * +open_file(char *shorty, char *mode) +{ + char fn[256]; + FILE *f; + + snprintf(fn, sizeof fn, "%s/%s.url", BASE_DIR, shorty); + + f = fopen(fn, mode); + if (! f) { + cgi_error("Unable to open database"); + } + + return f; +} + +void +shorten_url() +{ + char u[4096]; + size_t ulen; + char shorty[16]; + + ulen = cgi_item(u, sizeof u); + if (ulen == 0) { + cgi_error("No URL specified"); + } + + snprintf(shorty, sizeof shorty, "%08x.%04x", (unsigned int)time(NULL), getpid()); + + /* Put the URL into a file */ + { + FILE *f = open_file(shorty, "w"); + fprintf(f, "%s", u); + fclose(f); + } + + /* Report back */ + printf("Content-type: text/plain\r\n\r\n"); + printf("%s/%s\n", BASE_URL, shorty); +} + + +void +redirect(char *pi) +{ + int i; + + if (! pi) { + cgi_error("No short URL provided"); + } + + if (pi[0] != '/') { + cgi_error("Invalid PATH_INFO"); + } + pi += 1; + + for (i = 0; pi[i]; i += 1) { + if ((! isalnum(pi[i])) && + (pi[i] != '.')) { + cgi_error("Bad short URL"); + } + } + + /* Open file */ + { + char u[4096]; + FILE *f = open_file(pi, "r"); + + fgets(u, sizeof u, f); + fclose(f); + + printf("Location: %s\r\n", u); + } +} + + +void +list_links() +{ + char g[256]; + glob_t globbuf; + int i; + + snprintf(g, sizeof g, "%s/*.url", BASE_DIR); + + glob(g, 0, NULL, &globbuf); + + cgi_head("Clicko history"); + printf("
    \n"); + for (i = globbuf.gl_pathc - 1; i >= 0; i -= 1) { + FILE *f = fopen(globbuf.gl_pathv[i], "r"); + char url[4096]; + + fgets(url, sizeof url, f); + fclose(f); + + printf("
  • %s
  • \n", url, url); + } + printf("
\n"); + cgi_foot(); +} + +int +main(int argc, char *argv[]) +{ + if (-1 == cgi_init(argv)) { + fprintf(stderr, "Unable to initialize CGI.\n"); + return -1; + } + + while (1) { + char key[12]; + size_t klen; + + klen = cgi_item(key, sizeof key); + if (klen == 0) { + break; + } + switch (key[0]) { + case 'u': + shorten_url(); + return 0; + } + } + + { + char *pi = getenv("PATH_INFO"); + + if (pi) { + redirect(pi); + } + } + + list_links(); + + return 0; +} diff --git a/mail.cgi.c b/mail.cgi.c index ea9df69..69923f7 100644 --- a/mail.cgi.c +++ b/mail.cgi.c @@ -3,22 +3,73 @@ #include #include -const char *basepath = "/usr/share/IlohaMail/source"; +const char *baseurl = "https://woozle.org/mail.cgi/"; +const char *basepath = "/opt/roundcubemail"; int main(int argc, char *argv[]) { char *pathinfo = getenv("PATH_INFO"); + char *remaddr = getenv("REMOTE_ADDR"); + size_t pathlen = pathinfo?strlen(pathinfo):0; char filename[512]; + char *ext; - if ((! pathinfo) || - (! strcmp(pathinfo, "/")) || - (0 == strcmp(pathinfo, "/index.html"))) { - pathinfo = "/index.php"; + if ((! pathinfo) || (! remaddr) || (! getenv("HTTPS"))) { + printf("Location: %s\n", baseurl); + return 0; + } else if (0 == strcmp(pathinfo, "/index.html")) { + snprintf(filename, sizeof filename, "%s/index.php", basepath); + } else if (pathinfo[pathlen-1] == '/') { + snprintf(filename, sizeof filename, "%s%sindex.php", basepath, pathinfo); + } else { + snprintf(filename, sizeof filename, "%s%s", basepath, pathinfo); + } + + ext = strrchr(filename, '.'); + if (! ext) { + ext = ""; + } + + if (0 == strcmp(ext, ".php")) { + setenv("SCRIPT_FILENAME", filename, 1); + setenv("REDIRECT_STATUS", "fuck me", 1); + execl("/usr/bin/php-cgi", filename, NULL); + } else if (strstr(filename, "/config/") || + strstr(filename, "/logs/") || + strstr(filename, "/temp/")) { + printf("Content-type: text/plain\n\n[MESSAGE REDACTED]\n"); + } else { + FILE *f = fopen(filename, "r"); + char *ct = "application/octet-stream"; + + if (0 == strcmp(ext, ".css")) { + ct = "text/css"; + } else if (0 == strcmp(ext, ".html")) { + ct = "text/html"; + } else if (0 == strcmp(ext, ".js")) { + ct = "application/javascript"; + } else if (0 == strcmp(ext, ".png")) { + ct = "image/png"; + } else if (0 == strcmp(ext, ".jpg")) { + ct = "image/jpeg"; + } else if (0 == strcmp(ext, ".gif")) { + ct = "image/gif"; + } + + printf("Content-type: %s\n\n", ct); + + while (! feof(f)) { + char buf[4096]; + size_t len; + + + len = fread(buf, 1, sizeof buf, f); + if (len) { + fwrite(buf, 1, len, stdout); + } + } } - snprintf(filename, sizeof filename, "%s%s", basepath, pathinfo); - setenv("SCRIPT_FILENAME", filename, 1); - execl("/usr/bin/php-cgi", filename, NULL); return 0; } diff --git a/people.sh b/people.sh index 62ac05b..e693d69 100755 --- a/people.sh +++ b/people.sh @@ -8,8 +8,11 @@ echo ls /home/*/public_html/index.html | while read fn; do a=${fn#/home/} u=${a%/public_html/index.html} - l=/srv/www/woozle.org/~$u + tl=/srv/www/woozle.org/~$u + l=/srv/www/woozle.org/$u echo "* [$u](/~$u/)" - [ -h $l ] || ln -s /home/$u/public_html $l + for link in $tl $l; do + [ -h $link ] || ln -s /home/$u/public_html $link + done done diff --git a/woozle.mk b/woozle.mk index 3570b8c..eb2b875 100644 --- a/woozle.mk +++ b/woozle.mk @@ -1,11 +1,11 @@ PLAIN += . COPY += icon.png style.css style-black.css lists.cgi wishlist.cgi set.cgi $(TEMPLATE) -COPY += mail.cgi +COPY += mail.cgi ilohamail.cgi l.cgi COPY += google7f698b9893809122.html HTML += people.html $(DESTDIR)/people.html: people.sh template.html.m4 sh $< | $(MDWNTOHTML) > $@ -$(DESTDIR)/mail.cgi: mail.cgi.c +$(DESTDIR)/%.cgi: %.cgi.c $(CC) -Wall -Werror -o $@ $< diff --git a/xmas/2012/index.mdwn b/xmas/2012/index.mdwn new file mode 100644 index 0000000..bac7da1 --- /dev/null +++ b/xmas/2012/index.mdwn @@ -0,0 +1,16 @@ +Title: 2012 Christmas Letter + +Happy Holidays from Amy, Neale & Ginnie!  We’ve had a really busy but fun 2012.  Ginnie is now in 2nd grade, and we’re finding that every school year seems to have a theme of some sort of learning that she works on more than other things.  This year is definitely the year of being social.  It doesn’t hurt that her best friend lives directly across the street from us and is in the same class she is in, which is a mistake I’m sure the school won’t make when they put together class lists for next year! Ginnie continues to take Irish dance classes and goes to K-Kids once a week, which is a club through Kiwanis that concentrates on community service.  The community service seems to involve a lot of cookies and juice, but she does save a cookie for her mom some days, which could be considered doing the community a favor.  Ginnie is still a total ham and we love her to bits. + +Jada the Dog continues to claim that we don’t feed her enough and definitely don’t give her enough attention or walks.  She has been developing her trick of dragging her dog beds around the house to wherever the family is hanging out and flopping down on them, and she still squeaks her squeaky toys at 7pm sharp.  She is always on the lookout for sheep that need herding.  Dingo is getting pretty gray but is still as high-strung as he ever was.  We think that the mail carriers and meter-readers have figured out that he’s a total pushover, but we haven’t told Dingo that yet. + +Neale is absolutely loving his job and plans to work until he’s 150 years old.  He also loves plumbing.  He loves it so much that he installed the same toilet twice in our remodeled bathroom, just for fun.  Not because it was leaking.  He has become the go-to volunteer for at least two roller derby leagues in our area, and he’ll be Amy’s team’s Head NSO (non-skating official) this coming season.  His computer security training seminars are in the 5th year and still going strong. Neale and Amy went swing dancing for the first time in about 12 years recently, and it was really nice to rediscover how much fun that is! + +Amy is going into her 2nd season of roller derby with the Los Alamos Derby Dames.  They don’t have their season schedule hammered out just yet, but when they do, everyone should come and watch her team play!  And if you can’t do that, at least support your own town’s roller derby league and check out a “bout” sometime! Most leagues are non-profit and raise money for animal shelters, food banks, children’s hospitals and the like.  It’s also just a lot of fun to watch!  Amy also started nursing school in August.  She has three semesters and a lot of hard work left, but so far, so good!  It makes it a lot easier to have such a loving and supportive family in Neale and Ginnie. + +We get to end this letter with news that Amy's sister Kristen is a new mommy: Daphne was born on December 17. Mom and proud daddy Alex are doing great, and we can't wait to go see all three in San Francisco. + +With love from our crazy household to yours, + +Neale, Amy, Ginnie, Jada, Dingo and the gopher in the front yard. +