citadel
About: Citadel is an advanced messaging and collaboration system for groupware and BBS applications (preferred OS: Linux).
  Fossies Dox: citadel.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

serv_autocompletion.c
Go to the documentation of this file.
1/*
2 * Autocompletion of email recipients, etc.
3 *
4 * Copyright (c) 1987-2020 by the citadel.org team
5 *
6 * This program is open source software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15
16#include "ctdl_module.h"
17#include "serv_autocompletion.h"
18#include "config.h"
19
20
21/*
22 * Convert a structured name into a friendly name. Caller must free the
23 * returned pointer.
24 */
25char *n_to_fn(char *value) {
26 char *nnn = NULL;
27 int i;
28
29 nnn = malloc(strlen(value) + 10);
30 strcpy(nnn, "");
31 extract_token(&nnn[strlen(nnn)] , value, 3, ';', 999);
32 strcat(nnn, " ");
33 extract_token(&nnn[strlen(nnn)] , value, 1, ';', 999);
34 strcat(nnn, " ");
35 extract_token(&nnn[strlen(nnn)] , value, 2, ';', 999);
36 strcat(nnn, " ");
37 extract_token(&nnn[strlen(nnn)] , value, 0, ';', 999);
38 strcat(nnn, " ");
39 extract_token(&nnn[strlen(nnn)] , value, 4, ';', 999);
40 strcat(nnn, " ");
41 for (i=0; i<strlen(nnn); ++i) {
42 if (!strncmp(&nnn[i], " ", 2)) strcpy(&nnn[i], &nnn[i+1]);
43 }
44 striplt(nnn);
45 return(nnn);
46}
47
48
49
50
51/*
52 * Back end for cmd_auto()
53 */
54void hunt_for_autocomplete(long msgnum, char *search_string) {
55 struct CtdlMessage *msg;
56 struct vCard *v;
57 char *value = NULL;
58 char *value2 = NULL;
59 int i = 0;
60 char *nnn = NULL;
61
62 msg = CtdlFetchMessage(msgnum, 1);
63 if (msg == NULL) return;
64
65 v = vcard_load(msg->cm_fields[eMesageText]);
66 CM_Free(msg);
67
68 /*
69 * Try to match from a friendly name (the "fn" field). If there is
70 * a match, return the entry in the form of:
71 * Display Name <user@domain.org>
72 */
73 value = vcard_get_prop(v, "fn", 0, 0, 0);
74 if (value != NULL) if (bmstrcasestr(value, search_string)) {
75 value2 = vcard_get_prop(v, "email", 1, 0, 0);
76 if (value2 == NULL) value2 = "";
77 cprintf("%s <%s>\n", value, value2);
78 vcard_free(v);
79 return;
80 }
81
82 /*
83 * Try to match from a structured name (the "n" field). If there is
84 * a match, return the entry in the form of:
85 * Display Name <user@domain.org>
86 */
87 value = vcard_get_prop(v, "n", 0, 0, 0);
88 if (value != NULL) if (bmstrcasestr(value, search_string)) {
89
90 value2 = vcard_get_prop(v, "email", 1, 0, 0);
91 if (value2 == NULL) value2 = "";
92 nnn = n_to_fn(value);
93 cprintf("%s <%s>\n", nnn, value2);
94 free(nnn);
95 vcard_free(v);
96 return;
97 }
98
99 /*
100 * Try a partial match on all listed email addresses.
101 */
102 i = 0;
103 while (value = vcard_get_prop(v, "email", 1, i++, 0), value != NULL) {
104 if (bmstrcasestr(value, search_string)) {
105 if (vcard_get_prop(v, "fn", 0, 0, 0)) {
106 cprintf("%s <%s>\n", vcard_get_prop(v, "fn", 0, 0, 0), value);
107 }
108 else if (vcard_get_prop(v, "n", 0, 0, 0)) {
109 nnn = n_to_fn(vcard_get_prop(v, "n", 0, 0, 0));
110 cprintf("%s <%s>\n", nnn, value);
111 free(nnn);
112
113 }
114 else {
115 cprintf("%s\n", value);
116 }
117 vcard_free(v);
118 return;
119 }
120 }
121
122 vcard_free(v);
123}
124
125
126
127/*
128 * Attempt to autocomplete an address based on a partial...
129 */
130void cmd_auto(char *argbuf) {
131 char hold_rm[ROOMNAMELEN];
132 char search_string[256];
133 long *msglist = NULL;
134 int num_msgs = 0;
135 long *fts_msgs = NULL;
136 int fts_num_msgs = 0;
137 struct cdbdata *cdbfr;
138 int r = 0;
139 int i = 0;
140 int j = 0;
141 int search_match = 0;
142 char *rooms_to_try[] = { USERCONTACTSROOM, ADDRESS_BOOK_ROOM };
143
144 if (CtdlAccessCheck(ac_logged_in)) return;
145 extract_token(search_string, argbuf, 0, '|', sizeof search_string);
146 if (IsEmptyStr(search_string)) {
147 cprintf("%d You supplied an empty partial.\n",
149 return;
150 }
151
152 strcpy(hold_rm, CC->room.QRname); /* save current room */
153 cprintf("%d try these:\n", LISTING_FOLLOWS);
154
155 /*
156 * Gather up message pointers in rooms containing vCards
157 */
158 for (r=0; r < (sizeof(rooms_to_try) / sizeof(char *)); ++r) {
159 if (CtdlGetRoom(&CC->room, rooms_to_try[r]) == 0) {
160 cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long));
161 if (cdbfr != NULL) {
162 msglist = realloc(msglist, (num_msgs * sizeof(long)) + cdbfr->len + 1);
163 memcpy(&msglist[num_msgs], cdbfr->ptr, cdbfr->len);
164 num_msgs += (cdbfr->len / sizeof(long));
165 cdb_free(cdbfr);
166 }
167 }
168 }
169
170 /*
171 * Search-reduce the results if we have the full text index available
172 */
173 if (CtdlGetConfigInt("c_enable_fulltext")) {
174 CtdlModuleDoSearch(&fts_num_msgs, &fts_msgs, search_string, "fulltext");
175 if (fts_msgs) {
176 for (i=0; i<num_msgs; ++i) {
177 search_match = 0;
178 for (j=0; j<fts_num_msgs; ++j) {
179 if (msglist[i] == fts_msgs[j]) {
180 search_match = 1;
181 j = fts_num_msgs + 1; /* end the search */
182 }
183 }
184 if (!search_match) {
185 msglist[i] = 0; /* invalidate this result */
186 }
187 }
188 free(fts_msgs);
189 }
190 else {
191 /* If no results, invalidate the whole list */
192 free(msglist);
193 msglist = NULL;
194 num_msgs = 0;
195 }
196 }
197
198 /*
199 * Now output the ones that look interesting
200 */
201 if (num_msgs > 0) for (i=0; i<num_msgs; ++i) {
202 if (msglist[i] != 0) {
203 hunt_for_autocomplete(msglist[i], search_string);
204 }
205 }
206
207 cprintf("000\n");
208 if (strcmp(CC->room.QRname, hold_rm)) {
209 CtdlGetRoom(&CC->room, hold_rm); /* return to saved room */
210 }
211
212 if (msglist) {
213 free(msglist);
214 }
215
216}
217
218
219CTDL_MODULE_INIT(autocompletion)
220{
221 if (!threading)
222 {
223 CtdlRegisterProtoHook(cmd_auto, "AUTO", "Do recipient autocompletion");
224 }
225 /* return our module name for the log */
226 return "autocompletion";
227}
#define ROOMNAMELEN
Definition: citadel.h:56
int CtdlGetConfigInt(char *key)
Definition: config.c:417
#define CC
Definition: context.h:140
int CtdlAccessCheck(int)
Definition: user_ops.c:387
int CtdlGetRoom(struct ctdlroom *qrbuf, const char *room_name)
Definition: room_ops.c:342
void CtdlModuleDoSearch(int *num_msgs, long **search_msgs, const char *search_string, const char *func_name)
@ ac_logged_in
Definition: ctdl_module.h:244
void CtdlRegisterProtoHook(void(*handler)(char *), char *cmd, char *desc)
#define CTDL_MODULE_INIT(module_name)
Definition: ctdl_module.h:50
void cdb_free(struct cdbdata *cdb)
Definition: database.c:609
struct cdbdata * cdb_fetch(int cdb, const void *key, int keylen)
Definition: database.c:546
#define ILLEGAL_VALUE
Definition: ipcdef.h:16
#define LISTING_FOLLOWS
Definition: ipcdef.h:5
#define ERROR
Definition: ipcdef.h:9
void CM_Free(struct CtdlMessage *msg)
Definition: msgbase.c:310
struct CtdlMessage * CtdlFetchMessage(long msgnum, int with_body)
Definition: msgbase.c:1135
void * malloc(size_t)
void free(void *)
char * n_to_fn(char *value)
void cmd_auto(char *argbuf)
void hunt_for_autocomplete(long msgnum, char *search_string)
@ eMesageText
Definition: server.h:315
@ CDB_MSGLISTS
Definition: server.h:189
char * cm_fields[256]
Definition: server.h:37
size_t len
Definition: server.h:203
char * ptr
Definition: server.h:204
#define ADDRESS_BOOK_ROOM
Definition: sysconfig.h:74
#define USERCONTACTSROOM
Definition: sysconfig.h:67
void cprintf(const char *format,...)
Definition: sysdep.c:381