/* Proxy GETANNOTATION commands to backend */ int annotate_fetch_proxy(const char *server, const char *mbox_pat, const strarray_t *entry_pat, const strarray_t *attribute_pat) { struct backend *be; int i; char mytag[128]; assert(server && mbox_pat && entry_pat && attribute_pat); be = proxy_findserver(server, &imap_protocol, proxy_userid, &backend_cached, &backend_current, &backend_inbox, imapd_in); if (!be) return IMAP_SERVER_UNAVAILABLE; /* Send command to remote */ proxy_gentag(mytag, sizeof(mytag)); prot_printf(be->out, "%s GETANNOTATION \"%s\" (", mytag, mbox_pat); for (i = 0 ; i < entry_pat->count ; i++) { prot_printf(be->out, "%s\"%s\"", i ? " " : "", entry_pat->data[i]); } prot_printf(be->out, ") ("); for (i = 0 ; i < attribute_pat->count ; i++) { prot_printf(be->out, "%s\"%s\"", i ? " " : "", attribute_pat->data[i]); } prot_printf(be->out, ")\r\n"); prot_flush(be->out); /* Pipe the results. Note that backend-current may also pipe us other messages. */ pipe_until_tag(be, mytag, 0); return 0; }
struct backend *proxy_findinboxserver(const char *userid) { mbentry_t *mbentry = NULL; struct backend *s = NULL; char *inbox = mboxname_user_mbox(userid, NULL); int r = mboxlist_lookup(inbox, &mbentry, NULL); free(inbox); if (r) return NULL; if (mbentry->mbtype & MBTYPE_REMOTE) { s = proxy_findserver(mbentry->server, &imap_protocol, proxy_userid, &backend_cached, &backend_current, &backend_inbox, imapd_in); } mboxlist_entry_free(&mbentry); return s; }
/* Proxy SETANNOTATION commands to backend */ int annotate_store_proxy(const char *server, const char *mbox_pat, struct entryattlist *entryatts) { struct backend *be; struct entryattlist *e; struct attvaluelist *av; char mytag[128]; assert(server && mbox_pat && entryatts); be = proxy_findserver(server, &imap_protocol, proxy_userid, &backend_cached, &backend_current, &backend_inbox, imapd_in); if (!be) return IMAP_SERVER_UNAVAILABLE; /* Send command to remote */ proxy_gentag(mytag, sizeof(mytag)); prot_printf(be->out, "%s SETANNOTATION \"%s\" (", mytag, mbox_pat); for (e = entryatts; e; e = e->next) { prot_printf(be->out, "\"%s\" (", e->entry); for (av = e->attvalues; av; av = av->next) { prot_printf(be->out, "\"%s\" ", av->attrib); prot_printmap(be->out, av->value.s, av->value.len); prot_printf(be->out, "%s", av->next ? " " : ""); } prot_printf(be->out, ")"); if (e->next) prot_printf(be->out, " "); } prot_printf(be->out, ")\r\n"); prot_flush(be->out); /* Pipe the results. Note that backend-current may also pipe us other messages. */ pipe_until_tag(be, mytag, 0); return 0; }
struct backend *proxy_findinboxserver(const char *userid) { char inbox[MAX_MAILBOX_BUFFER]; struct mboxlist_entry *mbentry = NULL; struct backend *s = NULL; int r; r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, "INBOX", userid, inbox); if (r) return NULL; r = mboxlist_lookup(inbox, &mbentry, NULL); if (r) return NULL; if (mbentry->mbtype & MBTYPE_REMOTE) { s = proxy_findserver(mbentry->server, &imap_protocol, proxy_userid, &backend_cached, &backend_current, &backend_inbox, imapd_in); } mboxlist_entry_free(&mbentry); return s; }
static void proxy_part_filldata(partlist_t *part_list, int idx) { char mytag[128]; struct backend *be; partitem_t *item = &part_list->items[idx]; item->id = 0; item->available = 0; item->total = 0; item->quota = 0.; syslog(LOG_DEBUG, "checking free space on server '%s'", item->value); /* connect to server */ be = proxy_findserver(item->value, &imap_protocol, proxy_userid, &backend_cached, &backend_current, &backend_inbox, imapd_in); if (be) { uint64_t server_available = 0; uint64_t server_total = 0; const char *annot = (part_list->mode == PART_SELECT_MODE_FREESPACE_MOST) ? "freespace/total" : "freespace/percent/most"; struct buf cmd = BUF_INITIALIZER; int c; /* fetch annotation from remote */ proxy_gentag(mytag, sizeof(mytag)); if (CAPA(be, CAPA_METADATA)) { buf_printf(&cmd, "METADATA \"\" (\"/shared" IMAP_ANNOT_NS "%s\"", annot); } else { buf_printf(&cmd, "ANNOTATION \"\" \"" IMAP_ANNOT_NS "%s\" " "(\"value.shared\"", annot); } prot_printf(be->out, "%s GET%s)\r\n", mytag, buf_cstring(&cmd)); prot_flush(be->out); for (/* each annotation response */;;) { /* read a line */ c = prot_getc(be->in); if (c != '*') break; c = prot_getc(be->in); if (c != ' ') { /* protocol error */ c = EOF; break; } c = chomp(be->in, buf_cstring(&cmd)); if (c == ' ') c = prot_getc(be->in); if ((c == EOF) || (c != '\"')) { /* we don't care about this response */ eatline(be->in, c); continue; } /* read available */ c = getuint64(be->in, &server_available); if (c != ';') { c = EOF; break; } /* read total */ c = getuint64(be->in, &server_total); if (c != '\"') { c = EOF; break; } eatline(be->in, c); /* we don't care about the rest of the line */ } buf_free(&cmd); if (c != EOF) { prot_ungetc(c, be->in); /* we should be looking at the tag now */ eatline(be->in, c); } if (c == EOF) { /* uh oh, we're not happy */ fatal("Lost connection to backend", EC_UNAVAILABLE); } /* unique id */ item->id = idx; item->available = server_available; item->total = server_total; } }
char *find_free_server(void) { const char *servers = config_getstring(IMAPOPT_SERVERLIST); unsigned long max_avail = 0; char *server = NULL; if (servers) { char *tmpbuf, *cur_server, *next_server; char mytag[128]; struct backend *be; /* make a working copy of the list */ cur_server = tmpbuf = xstrdup(servers); while (cur_server) { /* eat any leading whitespace */ while (Uisspace(*cur_server)) cur_server++; if (!*cur_server) break; /* find end of server */ if ((next_server = strchr(cur_server, ' ')) || (next_server = strchr(cur_server, '\t'))) *next_server++ = '\0'; syslog(LOG_DEBUG, "checking free space on server '%s'", cur_server); /* connect to server */ be = proxy_findserver(cur_server, &imap_protocol, proxy_userid, &backend_cached, &backend_current, &backend_inbox, imapd_in); if (be) { unsigned avail = 0; int c; /* fetch annotation from remote */ proxy_gentag(mytag, sizeof(mytag)); prot_printf(be->out, "%s GETANNOTATION \"\" " "\"/vendor/cmu/cyrus-imapd/freespace\" " "\"value.shared\"\r\n", mytag); prot_flush(be->out); for (/* each annotation response */;;) { /* read a line */ c = prot_getc(be->in); if (c != '*') break; c = prot_getc(be->in); if (c != ' ') { /* protocol error */ c = EOF; break; } c = chomp(be->in, "ANNOTATION \"\" " "\"/vendor/cmu/cyrus-imapd/freespace\" " "(\"value.shared\" \""); if (c == EOF) { /* we don't care about this response */ eatline(be->in, c); continue; } /* read uidvalidity */ c = getuint32(be->in, &avail); if (c != '\"') { c = EOF; break; } eatline(be->in, c); /* we don't care about the rest of the line */ } if (c != EOF) { prot_ungetc(c, be->in); /* we should be looking at the tag now */ eatline(be->in, c); } if (c == EOF) { /* uh oh, we're not happy */ fatal("Lost connection to backend", EC_UNAVAILABLE); } if (avail > max_avail) { server = cur_server; max_avail = avail; } } /* move to next server */ cur_server = next_server; } if (server) server = xstrdup(server); free(tmpbuf); } return server; }