#include<u.h>
#include<libc.h>
#include<mp.h>
#include<libsec.h>
#include<regexp.h>
#include<bio.h>
#include<auth.h>
#include<fcall.h>
#include<thread.h>
#include<9p.h>
#include<mheap.h>
const char KEY[] = "a1b693d302635eb916d330aebd0bd5c8";
const char SECRET[] = "36eb40a37bf10381";
const char BOUNDARY[] = "thisismyboundarytherearemanylikeitbutthisoneismine";
char *token;
enum{
HEAP = 4972, /* Memory heap size */
};
/* Webfs */
char *webmtpt = "/mnt/web";
int ctlfd, conn;
int
webclone(int *c)
{
char buf[16];
int n, fd;
hpush();
if((fd = open(hprint("%s/clone", webmtpt), ORDWR)) < 0)
sysfatal("couldn't open %s: %r", buf);
if((n = read(fd, buf, sizeof buf-1)) < 0)
sysfatal("reading clone: %r");
if(n == 0)
sysfatal("short read on clone");
buf[n] = '\0';
*c = atoi(buf);
hpop();
return fd;
}
/* Formatters for URL and MD5 digest encoding */
#define ALPHANUM(x) ((x) >= 'a' && (x) <= 'z' || \
(x) >= 'A' && (x) <= 'Z' || \
(x) >= '0' && (x) <= '9' || \
(x) == '_' || (x) == '.' || (x) == '-')
#pragma varargck type "U" char*
static int
urlfmt(Fmt *fmt)
{
const char *buf;
char *p;
for(p = va_arg(fmt->args, char*), buf = ""; *p; p++)
if(ALPHANUM(*p))
buf = hprint("%s%c", buf, *p);
else
buf = hprint("%s%%%X", buf, (uchar)*p);
return fmtstrcpy(fmt, buf);
}
#pragma varargck type "M" uchar*
static int
digestfmt(Fmt *fmt)
{
char buf[MD5dlen*2+1];
uchar *p;
int i;
p = va_arg(fmt->args, uchar*);
for(i=0; i<MD5dlen; i++)
sprint(buf+2*i, "%.2ux", p[i]);
return fmtstrcpy(fmt, buf);
}
/* Flickr API requests */
typedef struct{
const char *name;
const char *value;
} Parameter;
typedef struct{
const char *url;
uint nparam;
Parameter params[16];
} Request;
Request fr;
int
pcmp(Parameter *a, Parameter *b)
{
int c = strcmp(a->name, b->name);
if(c != 0) return c;
return strcmp(a->value, b->value);
}
void
sortreq(Request *r)
{
qsort(r->params, r->nparam, sizeof(Parameter), (int(*)(void *, void *))pcmp);
}
void
add(Request *r, char *name, char *value)
{
r->params[r->nparam].name = hstrdup(name);
r->params[r->nparam++].value = hstrdup(value);
}
void
reset(Request *r)
{
r->nparam = 0;
r->url = "http://flickr.com/services/rest/";
}
void
sign(Request *r)
{
uchar digest[MD5dlen];
const char *buffer;
uint i;
sortreq(r);
buffer = hstrdup(SECRET);
for(i = 0; i < r->nparam; i++)
buffer = hprint("%s%s%s", buffer, r->params[i].name, r->params[i].value);
md5((uchar *)buffer, strlen(buffer), digest, nil);
add(r, "api_sig", hprint("%M", digest));
}
void
auth(Request *r)
{
add(r, "auth_token", token);
add(r, "api_key", KEY);
sign(r);
}
/* Flickr unique photo ids */
typedef struct{
char *id; /* if nil then it's a un-uploaded buffer not a reference */
union{
struct{char *farm, *secret, *server;};
struct{uchar *buf; ulong sz;};
};
} Pid;
/* Makes a get via webfs given a request */
Biobuf *
get(Request *r)
{
const char *buf;
int i, n;
Biobuf *fp;
/* Compile url */
buf = hprint("url %s", r->url);
for(i = 0; i < r->nparam; i++)
buf = hprint("%s%c%U=%U", buf, i == 0 ? '?':'&',
r->params[i].name, r->params[i].value);
if(write(ctlfd, buf, n = strlen(buf)) != n)
sysfatal("get: write: %r");
/* Response */
if((fp = Bopen(hprint("%s/%d/body", webmtpt, conn), OREAD)) == nil)
sysfatal("get: couldn't open body: %r");
return fp;
}
/* Posts a photo to flickr */
Biobuf