#include #include #include #include #define strscpy(d,s,n) do { strncpy(d, s, n); d[(n)-1] = 0; } while (0) #ifdef LITTLE_ENDIAN # define mklong(n) (((n)>>24) | (((n)>>8) & 0xFF00) | (((n)<<8) & 0xFF0000) | \ ((n)<<24)) # define mkshort(n) ((((n)>>8) | ((n)<<8)) & 0xFFFF) #else # define mklong(n) n # define mkshort(n) n #endif /* This should be the name of the count info file for each page to be * counted. It is treated as an extension; i.e. if the page that calls * this says it's "/", this will look for $HTMLDIR/$COUNTINFO; if the * calling page says it's "/hello.html", this will look for * $HTMLDIR/hello.html$COUNTINFO. The files should be writable by whoever * httpd runs CGIs as (unless this program is setuid). */ #ifndef COUNTINFO # define COUNTINFO ".counter" #endif /* This should be the path to the pbmplus ppm executables. */ #ifndef PPMPATH # define PPMPATH "/usr/local/netpbm/bin" #endif /* This should be the root HTML directory (relative to the documents). I.e. * if the document considers ~jsmith/ to be / , then this would be * /home/jsmith/public_html (for example). Note that there must be no * trailing slash. */ #define HTMLDIR "amitcp:httpd/htdocs" /* Header for an IFF ILBM file. */ struct ilbmhdr { long form; long size; long ilbm; long bmhd; long bmhdlen; short w, h, x, y; char planes, masking, compression, pad0; short transparentColor; char one[2]; short w2, h2; long cmap; long cmaplen; char map[2][3]; short pad; /* to multiple of 4 bytes */ long body; long bodylen; }; #include "digitdata.c" /**************/ /* An error occurred - print an error message and quit */ void doerror(char *s) { /* error message not wanted for */ /* printf("Content-Type: text/html\n\n" "\n\nError\n\n" "\n

Error!

\n" "Something has gone horribly wrong...

\n" "%s

\n\n\n", s);*/ printf("Content-Type: text/plain\n\n"); exit(20); } /* Translate a 2-digit hex number to a character */ char dohexnum(char *s) { char t[3]; strncpy(t, s, 2); t[2] = 0; if (!isxdigit(s[0]) || !isxdigit(s[1])) { doerror("Bad hex digit"); } return strtol(t, NULL, 16); } char tmp[64]; void killtmp() { remove(tmp); } main(int ac, char **av) { FILE *f; static char str[1024], s[1024]; char *u; short i, w, h, y, x, ndigits; long count, count2; /* count2 holds reversed value */ struct ilbmhdr hdr; char *image; sprintf(tmp, "temp:counter.%d", getpid()); atexit(killtmp); if (!(u = getenv("QUERY_STRING"))) doerror("Can't find request info"); /* Handle special "clear out temp files" command */ if (!strncmp(u, "tos52k", 6)) { system("rm temp:counter.#?"); u += 6; } strncpy(s, u, 1023); s[1023] = 0; *str = 0; while (u = strchr(s, '%')) { *u++ = 0; strcat(str, s); *++u = dohexnum(u); strcpy(s, u); } strcat(str, s); sprintf(s, "%s%s%s", HTMLDIR, str, COUNTINFO); f = fopen(s, "r"); if (!f || !fgets(str, sizeof(str), f)) doerror("Can't read count info"); fclose(f); count = atoi(str) + 1; sprintf(str, "%s.new", s); f = fopen(str, "w"); /* note: if we can't open or write, just leave the old file there */ if (f != NULL && fprintf(f, "%d\n", count) != EOF) { fclose(f); #ifdef AMIGA { char s2[256]; sprintf(s2, "%s.old", s); remove(s2); if (rename(s, s2) < 0 || rename(str, s) < 0) doerror("rename() failed"); remove(s2); } #else rename(str, s); #endif } else if (f != NULL) { fclose(f); remove(str); } f = fopen(tmp, "w"); if (!f) doerror("Can't create temporary file"); sprintf(s, "%d", count); w = strlen(s) * 12 - 3; h = 17; hdr.form = mklong('FORM'); hdr.ilbm = mklong('ILBM'); hdr.bmhd = mklong('BMHD'); hdr.bmhdlen = mklong(20); hdr.w = mkshort(w); hdr.h = mkshort(h); hdr.x = hdr.y = 0; hdr.planes = 1; hdr.compression = 0; hdr.masking = 0; /* should be transparent color */ hdr.pad0 = 0; hdr.transparentColor = 0; hdr.one[0] = hdr.one[1] = 1; hdr.w2 = hdr.w; hdr.h2 = hdr.h; hdr.cmap = mklong('CMAP'); hdr.cmaplen = mklong(8); hdr.map[0][0] = 0; hdr.map[0][1] = 0; hdr.map[0][2] = 0; hdr.map[1][0] = 255; hdr.map[1][1] = 255; hdr.map[1][2] = 255; hdr.body = mklong('BODY'); w = (w+18) & ~15; hdr.bodylen = mklong(w*h/8); hdr.size = mklong(sizeof(hdr) + w*h/8 - 8); if (!(image = calloc(1, w*h/8))) doerror("Out of memory"); count2 = ndigits = 0; while (count) { count2 = count2*10 + count%10; count /= 10; ++ndigits; } if (ndigits == 0) ndigits = 1; w /= 8; i = 0; /* used as flag for even/odd digits, and as error flag below */ x = 0; for (i = 0; i < ndigits; ++i) { count = count2 % 10; for (y = 0; y < h; ++y) { image[y*w+x] |= digitdata[i&1][count][y][0]; image[y*w+x+1] |= digitdata[i&1][count][y][1]; } ++x; if (i & 1) ++x; count2 /= 10; } if (1 != fwrite(&hdr, sizeof(hdr), 1, f) || 1 != fwrite(image, w*h, 1, f)) i = -1; fclose(f); if (i < 0) { remove(tmp); doerror("Can't write temporary file"); } sprintf(s, "%s/ilbmtoppm %s > %sX", PPMPATH, tmp, tmp); system(s); sprintf(s, "%s/ppmtogif -interlace %sX > %s", PPMPATH, tmp, tmp); system(s); sprintf(s, "%sX", tmp); remove(s); printf("Content-Type: image/gif\n\n"); fflush(stdout); f = fopen(tmp, "r"); if (!f) printf("oops, error\n"); while ((i = fread(s, 1, sizeof(s), f)) > 0) { fwrite(s, 1, i, stdout); fflush(stdout); } fclose(f); fflush(stdout); exit(i<0 ? 20 : 0); }