1 Description: Implement support for IMAP extension METADATA (rfc5464)
2 Provides get/set ANNOTATIONS support to the c-client library.
6 Origin: http://www-old.kolab.org/cgi-bin/viewcvs-kolab.cgi/server/patches/imap/
7 Bug-Debian: http://bugs.debian.org/456591
8 Last-Update: 2012-04-07
10 --- a/src/c-client/imap4r1.c
11 +++ b/src/c-client/imap4r1.c
13 #define MULTIAPPEND 13
15 #define MULTIAPPENDREDO 15
23 void imap_gc_body (BODY *body);
24 void imap_capability (MAILSTREAM *stream);
25 long imap_acl_work (MAILSTREAM *stream,char *command,IMAPARG *args[]);
26 +long imap_annotation_work (MAILSTREAM *stream,char *command,IMAPARG *args[]);
28 IMAPPARSEDREPLY *imap_send (MAILSTREAM *stream,char *cmd,IMAPARG *args[]);
29 IMAPPARSEDREPLY *imap_sout (MAILSTREAM *stream,char *tag,char *base,char **s);
30 long imap_soutr (MAILSTREAM *stream,char *string);
31 IMAPPARSEDREPLY *imap_send_astring (MAILSTREAM *stream,char *tag,char **s,
32 SIZEDTEXT *as,long wildok,char *limit);
33 +IMAPPARSEDREPLY *imap_send_qstring (MAILSTREAM *stream,char *tag,char **s,
34 + SIZEDTEXT *as,char *limit);
35 IMAPPARSEDREPLY *imap_send_literal (MAILSTREAM *stream,char *tag,char **s,
37 IMAPPARSEDREPLY *imap_send_spgm (MAILSTREAM *stream,char *tag,char *base,
38 @@ -2763,6 +2767,84 @@
39 args[0] = &ambx; args[1] = NIL;
40 return imap_acl_work (stream,"GETACL",args);
43 +/* IMAP set annotation
44 + * Accepts: mail stream
46 + * Returns: T on success, NIL on failure
49 +long imap_setannotation (MAILSTREAM *stream,ANNOTATION *annotation)
51 + IMAPARG *args[4],ambx,apth,aval;
54 + ambx.type = ASTRING;
55 + ambx.text = (void *) annotation->mbox;
58 + apth.type = QSTRING;
59 + apth.text = (void *) annotation->entry;
63 + ANNOTATION_VALUES *v;
65 + l = st = mail_newstringlist();
66 + v = annotation->values;
68 + l->text.size = strlen((char *) (l->text.data = (unsigned char*)cpystr(v->attr)));
69 + l->next = mail_newstringlist();
71 + l->text.size = strlen((char *) (l->text.data = (unsigned char*)cpystr(v->value)));
73 + l->next = mail_newstringlist();
80 + aval.text = (void *)st;
84 + ret = imap_annotation_work(stream, "SETANNOTATION",args);
85 + mail_free_stringlist(&st);
91 +/* IMAP get annotation
92 + * Accepts: mail stream
94 + * annotation entry list
95 + * annotation attribute list
96 + * Returns: T on success with data returned via callback, NIL on failure
99 +long imap_getannotation (MAILSTREAM *stream,char *mailbox,STRINGLIST *entries, STRINGLIST *attributes)
101 + IMAPARG *args[4],ambx,apth,aattr;
103 + ambx.type = ASTRING;
104 + ambx.text = (void*) mailbox;
109 + apth.text = (void*) entries;
112 + aattr.type = QLIST;
113 + aattr.text = (void*) attributes;
117 + ret = imap_annotation_work(stream, "GETANNOTATION",args);
122 * Accepts: mail stream
123 @@ -2815,6 +2897,16 @@
124 else mm_log ("ACL not available on this IMAP server",ERROR);
127 + long imap_annotation_work(MAILSTREAM *stream, char *command,IMAPARG *args[])
130 + IMAPPARSEDREPLY *reply;
131 + if (imap_OK (stream,reply = imap_send (stream,command,args)))
133 + else mm_log (reply->text,ERROR);
139 * Accepts: mail stream
140 @@ -2947,6 +3039,11 @@
141 if (reply = imap_send_astring (stream,tag,&s,&st,NIL,CMDBASE+MAXCOMMAND))
144 + case QSTRING: /* atom or string, must be literal? */
145 + st.size = strlen ((char *) (st.data = (unsigned char *) arg->text));
146 + if (reply = imap_send_qstring (stream,tag,&s,&st,CMDBASE+MAXCOMMAND))
149 case LITERAL: /* literal, as a stringstruct */
150 if (reply = imap_send_literal (stream,tag,&s,arg->text)) return reply;
152 @@ -2963,6 +3060,18 @@
153 while (list = list->next);
154 *s++ = ')'; /* close list */
156 + case QLIST: /* list of strings */
157 + list = (STRINGLIST *) arg->text;
158 + c = '('; /* open paren */
159 + do { /* for each list item */
160 + *s++ = c; /* write prefix character */
161 + if (reply = imap_send_qstring (stream,tag,&s,&list->text,
162 + CMDBASE+MAXCOMMAND)) return reply;
163 + c = ' '; /* prefix character for subsequent strings */
165 + while (list = list->next);
166 + *s++ = ')'; /* close list */
168 case SEARCHPROGRAM: /* search program */
169 if (reply = imap_send_spgm (stream,tag,CMDBASE,&s,arg->text,
171 @@ -3130,6 +3239,32 @@
172 mail_unlock (stream); /* unlock stream */
176 +/* IMAP send quoted-string
177 + * Accepts: MAIL stream
179 + * pointer to current position pointer of output bigbuf
180 + * atom-string to output
181 + * maximum to write as atom or qstring
182 + * Returns: error reply or NIL if success
185 +IMAPPARSEDREPLY *imap_send_qstring (MAILSTREAM *stream,char *tag,char **s,
186 + SIZEDTEXT *as,char *limit)
191 + /* in case needed */
192 + INIT (&st,mail_string,(void *) as->data,as->size);
193 + /* always write literal if no space */
194 + if ((*s + as->size) > limit) return imap_send_literal (stream,tag,s,&st);
196 + *(*s)++ = '"'; /* write open quote */
197 + for (j = 0; j < as->size; j++) *(*s)++ = as->data[j];
198 + *(*s)++ = '"'; /* write close quote */
202 /* IMAP send atom-string
203 * Accepts: MAIL stream
204 @@ -4059,6 +4194,50 @@
208 + else if (!strcmp (reply->key,"ANNOTATION") && (s = reply->text)){
210 + /* response looks like ANNOTATION "mailbox" "entry" ("attr" "value" ["attr" "value"]) ["entry" ("attr "value" ["attr" "value"] )]*/
211 + getannotation_t an = (getannotation_t) mail_parameters (NIL,GET_ANNOTATION,NIL);
213 + mbox = imap_parse_astring (stream, &s, reply,NIL);
216 + ANNOTATION * al = mail_newannotation();
217 + al->mbox = cpystr(mbox);
218 + t = imap_parse_astring (stream, &s, reply,NIL);
220 + STRINGLIST *strlist;
221 + if (s){while (*s == ' ')s++;}
223 + strlist = imap_parse_stringlist(stream, &s,reply);
225 + ANNOTATION_VALUES *vlIter, *vlBegin;
226 + vlIter = vlBegin = NIL;
230 + vlIter->next = mail_newannotationvalue();
231 + vlIter = vlIter->next;
233 + vlIter = mail_newannotationvalue();
236 + if ( strlist->text.size )
237 + vlIter->attr = cpystr (strlist->text.data);
238 + strlist = strlist->next;
239 + if(!strlist) continue;
240 + if ( strlist->text.size )
241 + vlIter->value = cpystr (strlist->text.data);
242 + strlist = strlist->next;
245 + al->values = vlBegin;
248 + mail_free_annotation(&al);
250 + fs_give ((void **)&mbox);
252 else if (!strcmp (reply->key,"ACL") && (s = reply->text) &&
253 (t = imap_parse_astring (stream,&s,reply,NIL))) {
254 getacl_t ar = (getacl_t) mail_parameters (NIL,GET_ACL,NIL);
255 --- a/src/c-client/imap4r1.h
256 +++ b/src/c-client/imap4r1.h
258 long imap_setquota (MAILSTREAM *stream,char *qroot,STRINGLIST *limits);
259 long imap_getquota (MAILSTREAM *stream,char *qroot);
260 long imap_getquotaroot (MAILSTREAM *stream,char *mailbox);
261 +long imap_getannotation (MAILSTREAM *stream,char *mailbox,STRINGLIST *entries,STRINGLIST *attributes);
262 +long imap_setannotation (MAILSTREAM *stream,ANNOTATION *annotation);
263 --- a/src/c-client/mail.c
264 +++ b/src/c-client/mail.c
266 static newsrcquery_t mailnewsrcquery = NIL;
267 /* ACL results callback */
268 static getacl_t mailaclresults = NIL;
269 +static getannotation_t mailannotationresults = NIL;
270 /* list rights results callback */
271 static listrights_t maillistrightsresults = NIL;
272 /* my rights results callback */
274 ret = (void *) (debugsensitive ? VOIDT : NIL);
277 + case SET_ANNOTATION:
278 + mailannotationresults = (getannotation_t) value;
279 + case GET_ANNOTATION:
280 + ret = (void *) mailannotationresults;
283 mailaclresults = (getacl_t) value;
285 @@ -5717,7 +5723,15 @@
286 return (ACLLIST *) memset (fs_get (sizeof (ACLLIST)),0,sizeof (ACLLIST));
289 +ANNOTATION *mail_newannotation (void)
291 + return (ANNOTATION *) memset (fs_get (sizeof (ANNOTATION)),0,sizeof(ANNOTATION));
294 +ANNOTATION_VALUES *mail_newannotationvalue (void)
296 + return (ANNOTATION_VALUES *) memset (fs_get (sizeof (ANNOTATION_VALUES)),0,sizeof(ANNOTATION_VALUES));
298 /* Mail instantiate new quotalist
299 * Returns: new quotalist
301 @@ -6040,6 +6054,25 @@
305 +static void mail_free_annotation_values(ANNOTATION_VALUES **val)
308 + if ((*val)->attr) fs_give ((void**) &(*val)->attr);
309 + if ((*val)->value) fs_give ((void**) &(*val)->value);
310 + mail_free_annotation_values (&(*val)->next);
311 + fs_give ((void **) val);
314 +void mail_free_annotation(ANNOTATION **al)
317 + if((*al)->mbox) fs_give ((void**) &(*al)->mbox);
318 + if((*al)->entry) fs_give ((void**) &(*al)->entry);
320 + mail_free_annotation_values(&(*al)->values);
321 + fs_give ((void **) al);
325 /* Mail garbage collect quotalist
326 * Accepts: pointer to quotalist pointer
327 --- a/src/c-client/mail.h
328 +++ b/src/c-client/mail.h
330 #define SET_SCANCONTENTS (long) 573
331 #define GET_MHALLOWINBOX (long) 574
332 #define SET_MHALLOWINBOX (long) 575
333 +#define GET_ANNOTATION (long) 576
334 +#define SET_ANNOTATION (long) 577
338 @@ -1048,6 +1050,24 @@
342 +/* ANNOTATION Response */
344 +#define ANNOTATION_VALUES struct annotation_value_list
349 + ANNOTATION_VALUES *next;
352 +#define ANNOTATION struct annotation
357 + ANNOTATION_VALUES * values;
360 /* Quota resource list */
362 #define QUOTALIST struct quota_list
363 @@ -1356,6 +1376,7 @@
364 typedef void (*logouthook_t) (void *data);
365 typedef char *(*sslclientcert_t) (void);
366 typedef char *(*sslclientkey_t) (void);
367 +typedef void (*getannotation_t) (MAILSTREAM *stream,ANNOTATION* annot);
371 @@ -1774,7 +1795,10 @@
372 SORTPGM *mail_newsortpgm (void);
373 THREADNODE *mail_newthreadnode (SORTCACHE *sc);
374 ACLLIST *mail_newacllist (void);
375 +ANNOTATION* mail_newannotation(void);
376 +ANNOTATION_VALUES* mail_newannotationvalue(void);
377 QUOTALIST *mail_newquotalist (void);
378 +void mail_free_annotation(ANNOTATION **a);
379 void mail_free_body (BODY **body);
380 void mail_free_body_data (BODY *body);
381 void mail_free_body_parameter (PARAMETER **parameter);
382 --- a/src/mtest/mtest.c
383 +++ b/src/mtest/mtest.c
389 +void mm_annotation (MAILSTREAM *stream, ANNOTATION *a);
392 * Accepts: MAIL stream
394 mail_setflag (stream,arg,"\\DELETED");
395 else puts ("?Bad message number");
399 + char parms[MAILTMPLEN];
400 + prompt("Annotation: ",parms);
402 + mail_parameters(stream,SET_ANNOTATION,mm_annotation);
403 + STRINGLIST *entries = mail_newstringlist();
404 + STRINGLIST *cur = entries;
405 + cur->text.size = strlen((char *) (cur->text.data = (unsigned char*)cpystr (parms)));
408 + STRINGLIST *attributes = mail_newstringlist();
410 + cur->text.size = strlen((char *) (cur->text.data = (unsigned char*)cpystr ("*")));
413 + imap_getannotation(stream,"INBOX",entries,attributes);
414 + mail_free_stringlist(&entries);
415 + mail_free_stringlist(&attributes);
419 case 'E': /* Expunge command */
420 mail_expunge (stream);
423 case '?': /* ? command */
424 puts ("Body, Check, Delete, Expunge, Find, GC, Headers, Literal,");
425 puts (" MailboxStatus, New Mailbox, Overview, Ping, Quit, Send, Type,");
426 - puts ("Undelete, Xit, +, -, or <RETURN> for next message");
427 + puts ("Undelete, Xit,Annotation, +, -, or <RETURN> for next message");
429 default: /* bogus command */
430 printf ("?Unrecognized command: %s\n",cmd);
433 /* Interfaces to C-client */
435 +void mm_annotation (MAILSTREAM *stream, ANNOTATION *a)
438 + fprintf(stderr,"mailbox: %s\nentry: %s\n",a->mbox,a->entry);
439 + ANNOTATION_VALUES * v = a->values;
441 + fprintf(stderr,"attr: %s, value: %s\n",v->attr,v->value);
448 void mm_searched (MAILSTREAM *stream,unsigned long number)