7 Qrpclog, // /smug/rpclog
8 Quploads, // /smug/uploads
10 Qnickctl, // /smug/nick/ctl
11 Qalbums, // /smug/nick/albums/
12 Qalbumsctl, // /smug/nick/albums/ctl
13 Qcategory, // /smug/nick/Category/
14 Qcategoryctl, // /smug/nick/Category/ctl
15 Qalbum, // /smug/nick/Category/Album/
16 Qalbumctl, // /smug/nick/Category/Album/ctl
17 Qalbumsettings, // /smug/nick/Category/Album/settings
18 Quploadfile, // /smug/nick/Category/Album/upload/file.jpg
19 Qimage, // /smug/nick/Category/Album/Image/
20 Qimagectl, // /smug/nick/Category/Album/Image/ctl
21 Qimageexif, // /smug/nick/Category/Album/Image/exif
22 Qimagesettings, // /smug/nick/Category/Album/Image/settings
23 Qimageurl, // /smug/nick/Category/Album/Image/url
24 Qimagefile, // /smug/nick/Category/Album/Image/file.jpg
31 fprint(2, "locked from %p\n", getcallerpc(&lk));
38 fprint(2, "unlocked from %p\n", getcallerpc(&lk));
42 //#define unlock myunlock
44 typedef struct Upload Upload;
46 typedef struct SmugFid SmugFid;
51 vlong category; // -1 for "albums"
60 #define QTYPE(p) ((p)&0xFF)
61 #define QARG(p) ((p)>>8)
62 #define QPATH(p, q) ((p)|((q)<<8))
92 newupload(SmugFid *sf, char *name)
96 char tmp[] = "/var/tmp/smugfs.XXXXXX";
98 if((fd = opentemp(tmp, ORDWR)) < 0)
101 for(i=0; i<nup; i++){
111 uploadrendez.l = &uploadlock;
112 proccreate(uploader, nil, STACKSIZE);
114 u = emalloc(sizeof *u);
117 up = erealloc(up, (nup+1)*sizeof up[0]);
120 qunlock(&uploadlock);
122 u->name = estrdup(name);
123 u->file = estrdup(tmp);
124 u->album = sf->album;
125 u->albumkey = estrdup(sf->albumkey);
132 closeupload(Upload *u)
135 fprint(2, "close %p from %p: %d\n", u, getcallerpc(&u), u->ref);
170 getuploadindex(SmugFid *sf, int *index)
176 for(i=0; i<nup; i++){
179 if(u->ref > 0 && !u->uploaded && u->album == sf->album && (*index)-- == 0){
180 qunlock(&uploadlock);
182 fprint(2, "bump %p from %p: %d\n", u, getcallerpc(&sf), u->ref);
188 qunlock(&uploadlock);
193 getuploadname(SmugFid *sf, char *name)
199 for(i=0; i<nup; i++){
202 if(u->ref > 0 && !u->uploaded && u->album == sf->album && strcmp(name, u->name) == 0){
203 qunlock(&uploadlock);
205 fprint(2, "bump %p from %p: %d\n", u, getcallerpc(&sf), u->ref);
211 qunlock(&uploadlock);
215 void doupload(Upload*);
226 for(i=0; i<nup; i++){
229 if(u->ref > 0 && u->ready && !u->uploading && !u->uploaded){
232 qunlock(&uploadlock);
235 fprint(2, "done %d\n", u->ref);
242 rsleep(&uploadrendez);
247 kickupload(Upload *u)
252 if((d = dirfstat(u->fd)) != nil)
253 u->length = d->length;
257 fprint(2, "kick %p from %p: %d\n", u, getcallerpc(&u), u->ref);
261 rwakeup(&uploadrendez);
262 qunlock(&uploadlock);
274 uchar digest[MD5dlen];
278 if((u->fd = open(u->file, OREAD)) < 0){
279 fprint(2, "cannot reopen temporary file %s: %r\n", u->file);
282 if((d = dirfstat(u->fd)) == nil){
283 fprint(2, "fstat: %r\n");
289 memset(&ds, 0, sizeof ds);
292 while((n = read(u->fd, buf, sizeof buf)) > 0){
293 md5((uchar*)buf, n, nil, &ds);
296 if(total != datalen){
297 fprint(2, "bad total: %lld %lld\n", total, datalen);
300 md5(nil, 0, digest, &ds);
303 fmtprint(&fmt, "PUT /%s HTTP/1.0\r\n", u->name);
304 fmtprint(&fmt, "Content-Length: %lld\r\n", datalen);
305 fmtprint(&fmt, "Content-MD5: %.16lH\r\n", digest);
306 fmtprint(&fmt, "X-Smug-SessionID: %s\r\n", sessid);
307 fmtprint(&fmt, "X-Smug-Version: %s\r\n", API_VERSION);
308 fmtprint(&fmt, "X-Smug-ResponseType: JSON\r\n");
309 // Can send X-Smug-ImageID instead to replace existing files.
310 fmtprint(&fmt, "X-Smug-AlbumID: %lld\r\n", u->album);
311 fmtprint(&fmt, "X-Smug-FileName: %s\r\n", u->name);
312 fmtprint(&fmt, "\r\n");
313 req = fmtstrflush(&fmt);
316 jv = jsonupload(&http, UPLOAD_HOST, req, u->fd, datalen);
319 fprint(2, "upload: %r\n");
329 rpclog("uploaded: %J", jv);
334 nickindex(char *name)
339 for(i=0; i<nnick; i++)
340 if(strcmp(nick[i], name) == 0)
342 v = smug("smugmug.users.getTree", "NickName", name, nil);
345 nick = erealloc(nick, (nnick+1)*sizeof nick[0]);
346 nick[nnick] = estrdup(name);
353 if(i < 0 || i >= nnick)
359 responderrstr(Req *r)
363 rerrstr(err, sizeof err);
368 xclone(Fid *oldfid, Fid *newfid)
372 if(oldfid->aux == nil)
375 sf = emalloc(sizeof *sf);
376 *sf = *(SmugFid*)oldfid->aux;
380 sf->albumkey = estrdup(sf->albumkey);
382 sf->imagekey = estrdup(sf->imagekey);
388 xdestroyfid(Fid *fid)
396 if(sf->upwriter && --sf->upload->nwriters == 0){
397 fprint(2, "should upload %s\n", sf->upload->name);
398 kickupload(sf->upload);
400 closeupload(sf->upload);
407 getcategories(SmugFid *sf)
411 v = smug("smugmug.categories.get", "NickName", nickname(sf->nickid), nil);
412 w = jincref(jwalk(v, "Categories"));
418 getcategorytree(SmugFid *sf)
422 v = smug("smugmug.users.getTree", "NickName", nickname(sf->nickid), nil);
423 w = jincref(jwalk(v, "Categories"));
429 getcategory(SmugFid *sf, vlong id)
434 v = getcategorytree(sf);
437 for(i=0; i<v->len; i++){
438 if(jint(jwalk(v->value[i], "id")) == id){
439 w = jincref(v->value[i]);
449 getcategoryid(SmugFid *sf, char *name)
455 v = getcategories(sf);
458 for(i=0; i<v->len; i++){
459 if(jstrcmp(jwalk(v->value[i], "Name"), name) == 0){
460 id = jint(jwalk(v->value[i], "id"));
474 getcategoryindex(SmugFid *sf, int i)
479 v = getcategories(sf);
482 if(i < 0 || i >= v->len){
486 id = jint(jwalk(v->value[i], "id"));
492 getalbum(SmugFid *sf, vlong albumid, char *albumkey)
497 snprint(id, sizeof id, "%lld", albumid);
498 v = smug("smugmug.albums.getInfo",
499 "AlbumID", id, "AlbumKey", albumkey,
500 "NickName", nickname(sf->nickid), nil);
501 w = jincref(jwalk(v, "Album"));
507 getalbums(SmugFid *sf)
511 if(sf->category >= 0)
512 v = getcategory(sf, sf->category);
514 v = smug("smugmug.albums.get",
515 "NickName", nickname(sf->nickid), nil);
516 w = jincref(jwalk(v, "Albums"));
522 getalbumid(SmugFid *sf, char *name, char **keyp)
532 for(i=0; i<v->len; i++){
533 if(jstrcmp(jwalk(v->value[i], "Title"), name) == 0){
534 id = jint(jwalk(v->value[i], "id"));
535 key = jstring(jwalk(v->value[i], "Key"));
536 if(id < 0 || key == nil){
541 *keyp = estrdup(key);
551 getalbumindex(SmugFid *sf, int i, char **keyp)
560 if(i < 0 || i >= v->len){
564 id = jint(jwalk(v->value[i], "id"));
565 key = jstring(jwalk(v->value[i], "Key"));
566 if(id < 0 || key == nil){
571 *keyp = estrdup(key);
577 getimages(SmugFid *sf, vlong albumid, char *albumkey)
582 snprint(id, sizeof id, "%lld", albumid);
583 v = smug("smugmug.images.get",
584 "AlbumID", id, "AlbumKey", albumkey,
585 "NickName", nickname(sf->nickid), nil);
586 w = jincref(jwalk(v, "Images"));
592 getimageid(SmugFid *sf, char *name, char **keyp)
600 id = strtol(name, &p, 10);
601 if(*p != 0 || *name == 0)
604 v = getimages(sf, sf->album, sf->albumkey);
607 for(i=0; i<v->len; i++){
608 if(jint(jwalk(v->value[i], "id")) == id){
609 key = jstring(jwalk(v->value[i], "Key"));
615 *keyp = estrdup(key);
625 getimageinfo(SmugFid *sf, vlong imageid, char *imagekey)
630 snprint(id, sizeof id, "%lld", imageid);
631 v = smug("smugmug.images.getInfo",
632 "ImageID", id, "ImageKey", imagekey,
633 "NickName", nickname(sf->nickid), nil);
634 w = jincref(jwalk(v, "Image"));
640 getimageexif(SmugFid *sf, vlong imageid, char *imagekey)
645 snprint(id, sizeof id, "%lld", imageid);
646 v = smug("smugmug.images.getEXIF",
647 "ImageID", id, "ImageKey", imagekey,
648 "NickName", nickname(sf->nickid), nil);
649 w = jincref(jwalk(v, "Image"));
655 getimageindex(SmugFid *sf, int i, char **keyp)
661 v = getimages(sf, sf->album, sf->albumkey);
664 if(i < 0 || i >= v->len){
668 id = jint(jwalk(v->value[i], "id"));
669 key = jstring(jwalk(v->value[i], "Key"));
670 if(id < 0 || key == nil){
675 *keyp = estrdup(key);
681 categoryname(SmugFid *sf)
686 v = getcategory(sf, sf->category);
687 s = jstring(jwalk(v, "Name"));
695 albumname(SmugFid *sf)
700 v = getalbum(sf, sf->album, sf->albumkey);
701 s = jstring(jwalk(v, "Title"));
709 imagename(SmugFid *sf)
714 v = getimageinfo(sf, sf->image, sf->imagekey);
715 s = jstring(jwalk(v, "FileName"));
719 s = smprint("%lld.jpg", sf->image); // TODO: use Format
725 imagelength(SmugFid *sf)
730 v = getimageinfo(sf, sf->image, sf->imagekey);
731 length = jint(jwalk(v, "Size"));
744 "MediumURL", "medium",
746 "XLargeURL", "xlarge",
747 "X2LargeURL", "xxlarge",
748 "X3LargeURL", "xxxlarge",
749 "OriginalURL", "original",
753 imageurl(SmugFid *sf)
759 v = getimageinfo(sf, sf->image, sf->imagekey);
760 for(i=nelem(urls)-1; i>=0; i--){
761 if((s = jstring(jwalk(v, urls[i].key))) != nil){
771 static char* imagestrings[] =
794 static char* albumbools[] =
818 static char* albumstrings[] =
840 return smprint("%#J\n", userinfo);
845 for(i=0; i<nup; i++){
848 if(u->ready && !u->uploaded && u->ref > 0)
849 fmtprint(&fmt, "%s %s%s\n", u->name, u->file, u->uploading ? " [uploading]" : "");
852 qunlock(&uploadlock);
853 return fmtstrflush(&fmt);
856 v = getcategories(sf);
860 v = getcategory(sf, sf->category);
864 v = getimages(sf, sf->album, sf->albumkey);
872 v = getimageinfo(sf, sf->image, sf->imagekey);
876 v = getimageinfo(sf, sf->image, sf->imagekey);
878 for(i=0; i<nelem(urls); i++)
879 if((s = jstring(jwalk(v, urls[i].key))) != nil)
880 fmtprint(&fmt, "%s %s\n", urls[i].name, s);
882 return fmtstrflush(&fmt);
885 v = getimageexif(sf, sf->image, sf->imagekey);
889 v = getalbum(sf, sf->album, sf->albumkey);
891 fmtprint(&fmt, "id\t%lld\n", jint(jwalk(v, "id")));
893 // TODO: SubCategory/id
894 // TODO: Community/id
896 fmtprint(&fmt, "Highlight\t%lld\n", jint(jwalk(v, "Highlight/id")));
897 fmtprint(&fmt, "Position\t%lld\n", jint(jwalk(v, "Position")));
898 fmtprint(&fmt, "ImageCount\t%lld\n", jint(jwalk(v, "ImageCount")));
899 for(i=0; i<nelem(albumbools); i++){
900 vv = jwalk(v, albumbools[i]);
902 fmtprint(&fmt, "%s\t%J\n", albumbools[i], vv);
904 for(i=0; i<nelem(albumstrings); i++){
905 s = jstring(jwalk(v, albumstrings[i]));
907 fmtprint(&fmt, "%s\t%s\n", albumstrings[i], s);
909 s = fmtstrflush(&fmt);
914 v = getimageinfo(sf, sf->image, sf->imagekey);
916 fmtprint(&fmt, "id\t%lld\n", jint(jwalk(v, "id")));
917 fmtprint(&fmt, "Position\t%lld\n", jint(jwalk(v, "Position")));
918 fmtprint(&fmt, "Serial\t%lld\n", jint(jwalk(v, "Serial")));
919 fmtprint(&fmt, "Size\t%lld\t%lldx%lld\n",
920 jint(jwalk(v, "Size")),
921 jint(jwalk(v, "Width")),
922 jint(jwalk(v, "Height")));
923 vv = jwalk(v, "Hidden");
924 fmtprint(&fmt, "Hidden\t%J\n", vv);
926 for(i=0; i<nelem(imagestrings); i++){
927 s = jstring(jwalk(v, imagestrings[i]));
929 fmtprint(&fmt, "%s\t%s\n", imagestrings[i], s);
931 s = fmtstrflush(&fmt);
938 s = smprint("%#J\n", v);
945 dostat(SmugFid *sf, Qid *qid, Dir *dir)
955 memset(&q, 0, sizeof q);
961 q.path = QPATH(sf->type, sf->nickid);
986 name = nickname(sf->nickid);
1002 name = categoryname(sf);
1004 q.path |= QPATH(0, sf->category << 8);
1010 q.path |= QPATH(0, sf->category << 8);
1013 name = albumname(sf);
1015 q.path |= QPATH(0, sf->album << 8);
1021 q.path |= QPATH(0, sf->album << 8);
1023 case Qalbumsettings:
1026 q.path |= QPATH(0, sf->album << 8);
1029 q.path |= QPATH(0, (uintptr)sf->upload << 8);
1032 name = sf->upload->name;
1033 if(sf->upload->fd >= 0){
1034 dd = dirfstat(sf->upload->fd);
1036 length = dd->length;
1040 length = sf->upload->length;
1041 if(!sf->upload->ready)
1046 name = smprint("%lld", sf->image);
1048 q.path |= QPATH(0, sf->image << 8);
1054 q.path |= QPATH(0, sf->image << 8);
1056 case Qimagesettings:
1059 q.path |= QPATH(0, sf->image << 8);
1063 q.path |= QPATH(0, sf->image << 8);
1067 q.path |= QPATH(0, sf->image << 8);
1070 name = imagename(sf);
1072 q.path |= QPATH(0, sf->image << 8);
1073 length = imagelength(sf);
1089 memset(dir, 0, sizeof *dir);
1090 dir->name = estrdup9p(name);
1091 dir->muid = estrdup9p("muid");
1096 dir->uid = estrdup9p(uid);
1097 dir->gid = estrdup9p("smugfs");
1099 dir->length = length;
1106 xwalk1(Fid *fid, char *name, Qid *qid)
1115 dotdot = strcmp(name, "..") == 0;
1120 return "file not found";
1125 if(strcmp(name, "ctl") == 0){
1129 if(strcmp(name, "uploads") == 0){
1130 sf->type = Quploads;
1133 if(strcmp(name, "rpclog") == 0){
1137 if((i = nickindex(name)) >= 0){
1150 if(strcmp(name, "ctl") == 0){
1151 sf->type = Qnickctl;
1154 if(strcmp(name, "albums") == 0){
1159 if((id = getcategoryid(sf, name)) >= 0){
1161 sf->type = Qcategory;
1173 if(strcmp(name, "ctl") == 0){
1177 if((id = getalbumid(sf, name, &key)) >= 0){
1190 if(sf->category == -1)
1193 sf->type = Qcategory;
1196 if(strcmp(name, "ctl") == 0){
1197 sf->type = Qalbumctl;
1200 if(strcmp(name, "settings") == 0){
1201 sf->type = Qalbumsettings;
1204 if((id = getimageid(sf, name, &key)) >= 0){
1210 if((u = getuploadname(sf, name)) != nil){
1212 sf->type = Quploadfile;
1225 if(strcmp(name, "ctl") == 0){
1226 sf->type = Qimagectl;
1229 if(strcmp(name, "url") == 0){
1230 sf->type = Qimageurl;
1233 if(strcmp(name, "settings") == 0){
1234 sf->type = Qimagesettings;
1237 if(strcmp(name, "exif") == 0){
1238 sf->type = Qimageexif;
1242 if(x && strcmp(name, x) == 0){
1244 sf->type = Qimagefile;
1250 dostat(sf, qid, nil);
1256 dodirgen(int i, Dir *d, void *v)
1266 xsf.type++; // ctl in every directory
1267 dostat(&xsf, nil, d);
1278 dostat(&xsf, nil, d);
1281 if(i < 0 || i >= nnick)
1285 dostat(&xsf, nil, d);
1291 dostat(&xsf, nil, d);
1294 if((id = getcategoryindex(sf, i)) < 0)
1296 xsf.type = Qcategory;
1298 dostat(&xsf, nil, d);
1303 if((id = getalbumindex(sf, i, &key)) < 0)
1308 dostat(&xsf, nil, d);
1314 xsf.type = Qalbumsettings;
1315 dostat(&xsf, nil, d);
1318 if((u = getuploadindex(sf, &i)) != nil){
1320 xsf.type = Quploadfile;
1321 dostat(&xsf, nil, d);
1325 if((id = getimageindex(sf, i, &key)) < 0)
1330 dostat(&xsf, nil, d);
1336 xsf.type = Qimagefile;
1337 dostat(&xsf, nil, d);
1341 xsf.type = Qimageexif;
1342 dostat(&xsf, nil, d);
1346 xsf.type = Qimagesettings;
1347 dostat(&xsf, nil, d);
1351 xsf.type = Qimageurl;
1352 dostat(&xsf, nil, d);
1362 dostat(r->fid->aux, nil, &r->d);
1375 if(r->d.uid[0] || r->d.gid[0] || r->d.muid[0] || ~r->d.mode != 0
1376 || ~r->d.atime != 0 || ~r->d.mtime != 0 || ~r->d.length != 0){
1377 respond(r, "invalid wstat");
1383 respond(r, "invalid wstat");
1385 // TODO: rename category
1387 snprint(strid, sizeof strid, "%lld", sf->album);
1388 v = ncsmug("smugmug.albums.changeSettings",
1389 "AlbumID", strid, "Title", r->d.name, nil);
1394 s = smprint("&AlbumID=%lld&", sf->album);
1397 jcacheflush("smugmug.albums.get&");
1401 respond(r, "invalid wstat");
1409 sf = emalloc(sizeof *sf);
1412 dostat(sf, &r->ofcall.qid, nil);
1413 r->fid->qid = r->ofcall.qid;
1422 if((r->ifcall.mode&~OTRUNC) > 2){
1423 respond(r, "permission denied");
1435 case Qalbumsettings:
1436 case Qimagesettings:
1440 if(r->ifcall.mode != OREAD){
1441 lock(&sf->upload->lk);
1442 if(sf->upload->ready){
1443 unlock(&sf->upload->lk);
1444 respond(r, "permission denied");
1448 sf->upload->nwriters++;
1449 unlock(&sf->upload->lk);
1454 if(r->ifcall.mode != OREAD){
1455 respond(r, "permission denied");
1461 r->ofcall.qid = r->fid->qid;
1471 char strid[50], *key;
1477 // Create new category.
1478 if(!(r->ifcall.perm&DMDIR))
1480 v = ncsmug("smugmug.categories.create",
1481 "Name", r->ifcall.name, nil);
1486 id = jint(jwalk(v, "Category/id"));
1488 fprint(2, "Create category: %J\n", v);
1493 sf->type = Qcategory;
1495 jcacheflush("method=smugmug.users.getTree&");
1496 jcacheflush("method=smugmug.categories.get&");
1497 dostat(sf, &r->ofcall.qid, nil);
1502 // Create new album.
1503 if(!(r->ifcall.perm&DMDIR))
1505 snprint(strid, sizeof strid, "%lld", sf->category);
1506 // Start with most restrictive settings.
1507 v = ncsmug("smugmug.albums.create",
1508 "Title", r->ifcall.name,
1509 "CategoryID", strid,
1511 "WorldSearchable", "0",
1512 "SmugSearchable", "0",
1518 id = jint(jwalk(v, "Album/id"));
1519 key = jstring(jwalk(v, "Album/Key"));
1520 if(id < 0 || key == nil){
1521 fprint(2, "Create album: %J\n", v);
1528 sf->albumkey = estrdup(key);
1530 jcacheflush("method=smugmug.users.getTree&");
1531 dostat(sf, &r->ofcall.qid, nil);
1536 // Upload image to album.
1537 if(r->ifcall.perm&DMDIR)
1539 u = newupload(sf, r->ifcall.name);
1546 sf->type = Quploadfile;
1547 dostat(sf, &r->ofcall.qid, nil);
1551 respond(r, "permission denied");
1555 writetofd(Req *r, int fd)
1560 while(total < r->ifcall.count){
1561 n = pwrite(fd, (char*)r->ifcall.data+total, r->ifcall.count-total, r->ifcall.offset+total);
1566 r->ofcall.count = r->ifcall.count;
1571 readfromfd(Req *r, int fd)
1574 n = pread(fd, r->ofcall.data, r->ifcall.count, r->ifcall.offset);
1577 r->ofcall.count = n;
1590 r->ofcall.count = 0;
1593 respond(r, "not implemented");
1601 dirread9p(r, dodirgen, sf);
1615 case Qimagesettings:
1616 case Qalbumsettings:
1623 if(url == nil || (fd = download(url, &hdr)) < 0){
1634 readfromfd(r, sf->upload->fd);
1650 r->ofcall.count = r->ifcall.count;
1651 sync = (r->ifcall.count==4 && memcmp(r->ifcall.data, "sync", 4) == 0);
1662 s = smprint("&NickName=%s&", nickname(sf->nickid));
1671 jcacheflush("smugmug.categories.get");
1675 s = smprint("&AlbumID=%lld&", sf->album);
1684 s = smprint("&ImageID=%lld&", sf->image);
1693 if(writetofd(r, sf->upload->fd) < 0){
1701 case Qimagesettings:
1702 case Qalbumsettings:
1703 s = (char*)r->ifcall.data; // lib9p nul-terminated it
1704 t = strpbrk(s, " \r\t\n");
1709 while(*t == ' ' || *t == '\r' || *t == '\t' || *t == '\n')
1712 p = strchr(t, '\n');
1716 respond(r, "newline in argument");
1719 if(sf->type == Qalbumsettings)
1721 snprint(strid, sizeof strid, "%lld", sf->image);
1722 v = ncsmug("smugmug.images.changeSettings",
1729 s = smprint("&ImageID=%lld&", sf->image);
1734 snprint(strid, sizeof strid, "%lld", sf->album);
1735 v = ncsmug("smugmug.albums.changeSettings",
1736 "AlbumID", strid, s, t, nil);
1741 s = smprint("&AlbumID=%lld&", sf->album);
1746 respond(r, "invalid control message");
1760 respond(r, "permission denied");
1764 case Qalbumsettings:
1766 case Qimagesettings:
1770 /* ignore remove request, but no error, so rm -r works */
1771 /* you can pretend they get removed and immediately grow back! */
1776 if(v && v->len > 0){
1777 respond(r, "directory not empty");
1780 snprint(id, sizeof id, "%lld", sf->category);
1781 v = ncsmug("smugmug.categories.delete",
1782 "CategoryID", id, nil);
1787 jcacheflush("smugmug.users.getTree");
1788 jcacheflush("smugmug.categories.get");
1793 v = getimages(sf, sf->album, sf->albumkey);
1794 if(v && v->len > 0){
1795 respond(r, "directory not empty");
1798 snprint(id, sizeof id, "%lld", sf->album);
1799 v = ncsmug("smugmug.albums.delete",
1800 "AlbumID", id, nil);
1805 jcacheflush("smugmug.users.getTree");
1806 jcacheflush("smugmug.categories.get");
1807 jcacheflush("smugmug.albums.get");
1813 snprint(id, sizeof id, "%lld", sf->image);
1814 v = ncsmug("smugmug.images.delete",
1815 "ImageID", id, nil);
1820 snprint(id, sizeof id, "ImageID=%lld&", sf->image);
1822 jcacheflush("smugmug.images.get&");
1832 rpclogflush(r->oldreq);
1841 xsrv.attach = xattach;
1843 xsrv.create = xcreate;
1846 xsrv.walk1 = xwalk1;
1847 xsrv.clone = xclone;
1848 xsrv.destroyfid = xdestroyfid;
1849 xsrv.remove = xremove;
1850 xsrv.write = xwrite;
1851 xsrv.flush = xflush;
1852 xsrv.wstat = xwstat;