4 * Autocompletion of email recipients, etc.
20 #include <sys/types.h>
22 #if TIME_WITH_SYS_TIME
23 # include <sys/time.h>
27 # include <sys/time.h>
38 #include "serv_extensions.h"
39 #include "sysdep_decls.h"
40 #include "citserver.h"
49 #include "serv_autocompletion.h"
59 * Convert a structured name into a friendly name. Caller must free the
62 char *n_to_fn(char *value) {
66 nnn = malloc(strlen(value) + 10);
68 extract_token(&nnn[strlen(nnn)] , value, 3, ';', 999); strcat(nnn, " ");
69 extract_token(&nnn[strlen(nnn)] , value, 1, ';', 999); strcat(nnn, " ");
70 extract_token(&nnn[strlen(nnn)] , value, 2, ';', 999); strcat(nnn, " ");
71 extract_token(&nnn[strlen(nnn)] , value, 0, ';', 999); strcat(nnn, " ");
72 extract_token(&nnn[strlen(nnn)] , value, 4, ';', 999); strcat(nnn, " ");
73 for (i=0; i<strlen(nnn); ++i) {
74 if (!strncmp(&nnn[i], " ", 2)) strcpy(&nnn[i], &nnn[i+1]);
84 * Back end for cmd_auto()
86 void hunt_for_autocomplete(long msgnum, void *data) {
88 struct CtdlMessage *msg;
95 search_string = (char *) data;
97 msg = CtdlFetchMessage(msgnum, 1);
98 if (msg == NULL) return;
100 v = vcard_load(msg->cm_fields['M']);
101 CtdlFreeMessage(msg);
104 * Try to match from a friendly name (the "fn" field). If there is a
105 * match, return the entry in the form of: Display Name <user@domain.org>
107 value = vcard_get_prop(v, "fn", 0, 0, 0);
108 if (value != NULL) if (bmstrcasestr(value, search_string)) {
109 value2 = vcard_get_prop(v, "email", 1, 0, 0);
110 if (value2 == NULL) value2 = "";
111 cprintf("%s <%s>\n", value, value2);
117 * Try to match from a structured name (the "n" field). If there is a
118 * match, return the entry in the form of: Display Name <user@domain.org>
120 value = vcard_get_prop(v, "n", 0, 0, 0);
121 if (value != NULL) if (bmstrcasestr(value, search_string)) {
123 value2 = vcard_get_prop(v, "email", 1, 0, 0);
124 if (value2 == NULL) value2 = "";
125 nnn = n_to_fn(value);
126 cprintf("%s <%s>\n", nnn, value2);
133 * Try a partial match on all listed email addresses.
136 while (value = vcard_get_prop(v, "email", 1, i++, 0), value != NULL) {
137 if (bmstrcasestr(value, search_string)) {
138 if (vcard_get_prop(v, "fn", 0, 0, 0)) {
139 cprintf("%s <%s>\n", vcard_get_prop(v, "fn", 0, 0, 0), value);
141 else if (vcard_get_prop(v, "n", 0, 0, 0)) {
142 nnn = n_to_fn(vcard_get_prop(v, "n", 0, 0, 0));
143 cprintf("%s <%s>\n", nnn, value);
148 cprintf("%s\n", value);
161 * Attempt to autocomplete an address based on a partial...
163 void cmd_auto(char *argbuf) {
164 char hold_rm[ROOMNAMELEN];
165 char search_string[256];
167 if (CtdlAccessCheck(ac_logged_in)) return;
168 extract_token(search_string, argbuf, 0, '|', sizeof search_string);
169 if (strlen(search_string) == 0) {
170 cprintf("%d You supplied an empty partial.\n", ERROR + ILLEGAL_VALUE);
174 strcpy(hold_rm, CC->room.QRname); /* save current room */
175 cprintf("%d try these:\n", LISTING_FOLLOWS);
177 /* Take a spin through the user's personal address book */
178 if (getroom(&CC->room, USERCONTACTSROOM) == 0) {
179 CtdlForEachMessage(MSGS_ALL, 0, "text/x-vcard", NULL,
180 hunt_for_autocomplete, search_string);
183 /* FIXME try the global address book */
184 if (getroom(&CC->room, ADDRESS_BOOK_ROOM) == 0) {
185 CtdlForEachMessage(MSGS_ALL, 0, "text/x-vcard", NULL,
186 hunt_for_autocomplete, search_string);
190 if (strcmp(&CC->room.QRname, hold_rm)) {
191 getroom(&CC->room, hold_rm); /* return to saved room */
196 char *serv_autocompletion_init(void)
198 CtdlRegisterProtoHook(cmd_auto, "AUTO", "Perform recipient autocompletion");