Mercurial > ~mikael > mcabber > hg
annotate mcabber/src/compl.c @ 1197:6f602d3270a4
Add /pgp [-]force
With this command it becomes possible to enforce PGP encryption without
checking if the remote client has PGP support. It can be used to send
encrypted offline messages too.
author | Mikael Berthe <mikael@lilotux.net> |
---|---|
date | Fri, 27 Apr 2007 00:37:57 +0200 |
parents | b9698c89f46d |
children | 2de8f8ba1f34 |
rev | line source |
---|---|
94 | 1 /* |
2 * compl.c -- Completion system | |
393 | 3 * |
699 | 4 * Copyright (C) 2005, 2006 Mikael Berthe <bmikael@lists.lilotux.net> |
94 | 5 * |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or (at | |
9 * your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, but | |
12 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 * General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |
19 * USA | |
20 */ | |
21 | |
22 /* Usage, basically: | |
23 * - new_completion(); // 1. Initialization | |
24 * - complete(); // 2. 1st completion | |
25 * - cancel_completion(); // 3a. 2nd completion / cancel previous | |
26 * - complete(); // 3b. 2nd completion / complete | |
27 * ... | |
28 * - done_completion(); // n. finished -- free allocated areas | |
29 * | |
30 */ | |
31 | |
32 #include <string.h> | |
33 | |
34 #include "compl.h" | |
225 | 35 #include "roster.h" |
757
ae23c8826efb
Improve completion for the "/event" command
Mikael Berthe <mikael@lilotux.net>
parents:
735
diff
changeset
|
36 #include "events.h" |
94 | 37 |
38 // Completion structure | |
39 typedef struct { | |
40 GSList *list; // list of matches | |
41 guint len_prefix; // length of text already typed by the user | |
42 guint len_compl; // length of the last completion | |
43 GSList *next; // pointer to next completion to try | |
44 } compl; | |
45 | |
46 // Category structure | |
47 typedef struct { | |
48 guint flag; | |
49 GSList *words; | |
50 } category; | |
51 | |
52 static GSList *Categories; | |
53 static compl *InputCompl; | |
54 | |
55 // new_completion(prefix, compl_cat) | |
56 // . prefix = beginning of the word, typed by the user | |
57 // . compl_cat = pointer to a completion category list (list of *char) | |
894
f76b32ff2f14
done_completion(): free all allocated memory
Mikael Berthe <mikael@lilotux.net>
parents:
820
diff
changeset
|
58 // Set the InputCompl pointer to an allocated compl structure. |
f76b32ff2f14
done_completion(): free all allocated memory
Mikael Berthe <mikael@lilotux.net>
parents:
820
diff
changeset
|
59 // done_completion() must be called when finished. |
94 | 60 void new_completion(char *prefix, GSList *compl_cat) |
61 { | |
62 compl *c; | |
63 GSList *sl_cat; | |
735 | 64 size_t len = strlen(prefix); |
94 | 65 |
66 if (InputCompl) { // This should not happen, but hey... | |
67 cancel_completion(); | |
68 } | |
69 | |
70 c = g_new0(compl, 1); | |
71 // Build the list of matches | |
72 for (sl_cat=compl_cat; sl_cat; sl_cat = g_slist_next(sl_cat)) { | |
73 char *word = sl_cat->data; | |
104 | 74 if (!strncasecmp(prefix, word, len)) { |
98 | 75 if (strlen(word) != len) |
76 c->list = g_slist_append(c->list, g_strdup(word+len)); // TODO sort | |
94 | 77 } |
78 } | |
79 c->next = c->list; | |
80 InputCompl = c; | |
81 } | |
82 | |
83 // done_completion(); | |
84 void done_completion(void) | |
85 { | |
894
f76b32ff2f14
done_completion(): free all allocated memory
Mikael Berthe <mikael@lilotux.net>
parents:
820
diff
changeset
|
86 GSList *clp; |
f76b32ff2f14
done_completion(): free all allocated memory
Mikael Berthe <mikael@lilotux.net>
parents:
820
diff
changeset
|
87 |
98 | 88 if (!InputCompl) return; |
89 | |
894
f76b32ff2f14
done_completion(): free all allocated memory
Mikael Berthe <mikael@lilotux.net>
parents:
820
diff
changeset
|
90 // Free the current completion list |
f76b32ff2f14
done_completion(): free all allocated memory
Mikael Berthe <mikael@lilotux.net>
parents:
820
diff
changeset
|
91 for (clp = InputCompl->list; clp; clp = g_slist_next(clp)) |
f76b32ff2f14
done_completion(): free all allocated memory
Mikael Berthe <mikael@lilotux.net>
parents:
820
diff
changeset
|
92 g_free(clp->data); |
94 | 93 g_slist_free(InputCompl->list); |
94 g_free(InputCompl); | |
95 InputCompl = NULL; | |
96 } | |
97 | |
98 // cancel_completion() | |
99 // Returns the number of chars to delete to cancel the completion | |
100 //guint cancel_completion(compl *c) | |
101 guint cancel_completion(void) | |
102 { | |
98 | 103 if (!InputCompl) return 0; |
94 | 104 return InputCompl->len_compl; |
105 } | |
106 | |
107 // Returns pointer to text to insert, NULL if no completion. | |
108 const char *complete() | |
109 { | |
110 compl* c = InputCompl; | |
111 char *r; | |
98 | 112 |
113 if (!InputCompl) return NULL; | |
114 | |
94 | 115 if (!c->next) { |
116 c->next = c->list; // back to the beginning | |
117 c->len_compl = 0; | |
118 return NULL; | |
119 } | |
120 r = (char*)c->next->data; | |
121 c->next = g_slist_next(c->next); | |
122 c->len_compl = strlen(r); | |
123 return r; | |
124 } | |
125 | |
126 | |
127 /* Categories functions */ | |
128 | |
95 | 129 // compl_add_category_word(categ, command) |
130 // Adds a keyword as a possible completion in category categ. | |
131 void compl_add_category_word(guint categ, const char *word) | |
94 | 132 { |
133 GSList *sl_cat; | |
134 category *cat; | |
121 | 135 char *nword; |
94 | 136 // Look for category |
137 for (sl_cat=Categories; sl_cat; sl_cat = g_slist_next(sl_cat)) { | |
138 if (categ == ((category*)sl_cat->data)->flag) | |
139 break; | |
140 } | |
141 if (!sl_cat) { // Category not found, let's create it | |
142 cat = g_new0(category, 1); | |
143 cat->flag = categ; | |
144 Categories = g_slist_append(Categories, cat); | |
145 } else | |
146 cat = (category*)sl_cat->data; | |
147 | |
121 | 148 // If word is not space-terminated, we add one trailing space |
149 for (nword = (char*)word; *nword; nword++) | |
150 ; | |
151 if (nword > word) nword--; | |
152 if (*nword != ' ') { // Add a space | |
153 nword = g_new(char, strlen(word)+2); | |
154 strcpy(nword, word); | |
155 strcat(nword, " "); | |
156 } else { // word is fine | |
157 nword = g_strdup(word); | |
158 } | |
159 | |
94 | 160 // TODO Check word does not already exist |
121 | 161 cat->words = g_slist_append(cat->words, nword); // TODO sort |
94 | 162 } |
163 | |
284
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
164 // compl_del_category_word(categ, command) |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
165 // Removes a keyword from category categ in completion list. |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
166 void compl_del_category_word(guint categ, const char *word) |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
167 { |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
168 GSList *sl_cat, *sl_elt; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
169 category *cat; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
170 char *nword; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
171 // Look for category |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
172 for (sl_cat=Categories; sl_cat; sl_cat = g_slist_next(sl_cat)) { |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
173 if (categ == ((category*)sl_cat->data)->flag) |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
174 break; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
175 } |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
176 if (!sl_cat) return; // Category not found, finished! |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
177 |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
178 cat = (category*)sl_cat->data; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
179 |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
180 // If word is not space-terminated, we add one trailing space |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
181 for (nword = (char*)word; *nword; nword++) |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
182 ; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
183 if (nword > word) nword--; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
184 if (*nword != ' ') { // Add a space |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
185 nword = g_new(char, strlen(word)+2); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
186 strcpy(nword, word); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
187 strcat(nword, " "); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
188 } else { // word is fine |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
189 nword = g_strdup(word); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
190 } |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
191 |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
192 sl_elt = cat->words; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
193 while (sl_elt) { |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
194 if (!strcasecmp((char*)sl_elt->data, nword)) { |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
195 g_free(sl_elt->data); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
196 cat->words = g_slist_delete_link(cat->words, sl_elt); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
197 break; // Only remove first occurence |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
198 } |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
199 sl_elt = g_slist_next(sl_elt); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
200 } |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
201 } |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
202 |
95 | 203 // compl_get_category_list() |
204 // Returns a slist of all words in the categories specified by the given flags | |
1076
b9698c89f46d
Fix memory leak in scr_handle_tab()
Mikael Berthe <mikael@lilotux.net>
parents:
894
diff
changeset
|
205 // Iff this function sets *dynlist to TRUE, then the caller must free the |
b9698c89f46d
Fix memory leak in scr_handle_tab()
Mikael Berthe <mikael@lilotux.net>
parents:
894
diff
changeset
|
206 // whole list after use. |
b9698c89f46d
Fix memory leak in scr_handle_tab()
Mikael Berthe <mikael@lilotux.net>
parents:
894
diff
changeset
|
207 GSList *compl_get_category_list(guint cat_flags, guint *dynlist) |
94 | 208 { |
209 GSList *sl_cat; | |
1076
b9698c89f46d
Fix memory leak in scr_handle_tab()
Mikael Berthe <mikael@lilotux.net>
parents:
894
diff
changeset
|
210 |
b9698c89f46d
Fix memory leak in scr_handle_tab()
Mikael Berthe <mikael@lilotux.net>
parents:
894
diff
changeset
|
211 *dynlist = FALSE; |
b9698c89f46d
Fix memory leak in scr_handle_tab()
Mikael Berthe <mikael@lilotux.net>
parents:
894
diff
changeset
|
212 |
94 | 213 // Look for category |
214 // XXX Actually that's not that simple... cat_flags can be a combination | |
215 // of several flags! | |
216 for (sl_cat=Categories; sl_cat; sl_cat = g_slist_next(sl_cat)) { | |
217 if (cat_flags == ((category*)sl_cat->data)->flag) | |
218 break; | |
219 } | |
220 if (sl_cat) // Category was found, easy... | |
221 return ((category*)sl_cat->data)->words; | |
222 | |
225 | 223 // Handle dynamic SLists |
1076
b9698c89f46d
Fix memory leak in scr_handle_tab()
Mikael Berthe <mikael@lilotux.net>
parents:
894
diff
changeset
|
224 *dynlist = TRUE; |
225 | 225 if (cat_flags == COMPL_GROUPNAME) { |
226 return compl_list(ROSTER_TYPE_GROUP); | |
227 } | |
228 if (cat_flags == COMPL_JID) { | |
229 return compl_list(ROSTER_TYPE_USER); | |
230 } | |
501
7c1ca00070e8
Add COMPL_RESOURCE (resource completion category)
Mikael Berthe <mikael@lilotux.net>
parents:
393
diff
changeset
|
231 if (cat_flags == COMPL_RESOURCE) { |
792
89ad7b530b3c
MUC: Fix completion for UTF-8 nicknames
Mikael Berthe <mikael@lilotux.net>
parents:
757
diff
changeset
|
232 return buddy_getresources_locale(NULL); |
501
7c1ca00070e8
Add COMPL_RESOURCE (resource completion category)
Mikael Berthe <mikael@lilotux.net>
parents:
393
diff
changeset
|
233 } |
757
ae23c8826efb
Improve completion for the "/event" command
Mikael Berthe <mikael@lilotux.net>
parents:
735
diff
changeset
|
234 if (cat_flags == COMPL_EVENTSID) { |
820
80bd7f49075f
Allow '*' in /event command
Mikael Berthe <mikael@lilotux.net>
parents:
792
diff
changeset
|
235 return evs_geteventslist(TRUE); |
757
ae23c8826efb
Improve completion for the "/event" command
Mikael Berthe <mikael@lilotux.net>
parents:
735
diff
changeset
|
236 } |
225 | 237 |
1076
b9698c89f46d
Fix memory leak in scr_handle_tab()
Mikael Berthe <mikael@lilotux.net>
parents:
894
diff
changeset
|
238 *dynlist = FALSE; |
94 | 239 return NULL; |
240 } | |
241 | |
580 | 242 /* vim: set expandtab cindent cinoptions=>2\:2(0: For Vim users... */ |