1 /*
2  * cmd_ac.c
3  * vim: expandtab:ts=4:sts=4:sw=4
4  *
5  * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
6  * Copyright (C) 2019 Michael Vetter <jubalh@iodoru.org>
7  *
8  * This file is part of Profanity.
9  *
10  * Profanity is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * Profanity is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Profanity.  If not, see <https://www.gnu.org/licenses/>.
22  *
23  * In addition, as a special exception, the copyright holders give permission to
24  * link the code of portions of this program with the OpenSSL library under
25  * certain conditions as described in each individual source file, and
26  * distribute linked combinations including the two.
27  *
28  * You must obey the GNU General Public License in all respects for all of the
29  * code used other than OpenSSL. If you modify file(s) with this exception, you
30  * may extend this exception to your version of the file(s), but you are not
31  * obligated to do so. If you do not wish to do so, delete this exception
32  * statement from your version. If you delete this exception statement from all
33  * source files in the program, then also delete it here.
34  *
35  */
36 
37 #include "config.h"
38 
39 #include <stdlib.h>
40 #include <string.h>
41 #include <assert.h>
42 #include <libgen.h>
43 #include <dirent.h>
44 
45 #include "common.h"
46 #include "config/preferences.h"
47 #include "config/scripts.h"
48 #include "command/cmd_ac.h"
49 #include "command/cmd_funcs.h"
50 #include "tools/parser.h"
51 #include "plugins/plugins.h"
52 #include "ui/win_types.h"
53 #include "ui/window_list.h"
54 #include "xmpp/muc.h"
55 #include "xmpp/xmpp.h"
56 #include "xmpp/roster_list.h"
57 #include "ui/buffer.h"
58 
59 #ifdef HAVE_LIBGPGME
60 #include "pgp/gpg.h"
61 #endif
62 
63 #ifdef HAVE_OMEMO
64 #include "omemo/omemo.h"
65 #endif
66 
67 static char* _sub_autocomplete(ProfWin* window, const char* const input, gboolean previous);
68 static char* _notify_autocomplete(ProfWin* window, const char* const input, gboolean previous);
69 static char* _theme_autocomplete(ProfWin* window, const char* const input, gboolean previous);
70 static char* _autoaway_autocomplete(ProfWin* window, const char* const input, gboolean previous);
71 static char* _autoconnect_autocomplete(ProfWin* window, const char* const input, gboolean previous);
72 static char* _account_autocomplete(ProfWin* window, const char* const input, gboolean previous);
73 static char* _who_autocomplete(ProfWin* window, const char* const input, gboolean previous);
74 static char* _roster_autocomplete(ProfWin* window, const char* const input, gboolean previous);
75 static char* _bookmark_autocomplete(ProfWin* window, const char* const input, gboolean previous);
76 #ifdef HAVE_LIBOTR
77 static char* _otr_autocomplete(ProfWin* window, const char* const input, gboolean previous);
78 #endif
79 #ifdef HAVE_LIBGPGME
80 static char* _pgp_autocomplete(ProfWin* window, const char* const input, gboolean previous);
81 static char* _ox_autocomplete(ProfWin* window, const char* const input, gboolean previous);
82 #endif
83 #ifdef HAVE_OMEMO
84 static char* _omemo_autocomplete(ProfWin* window, const char* const input, gboolean previous);
85 #endif
86 static char* _connect_autocomplete(ProfWin* window, const char* const input, gboolean previous);
87 static char* _alias_autocomplete(ProfWin* window, const char* const input, gboolean previous);
88 static char* _join_autocomplete(ProfWin* window, const char* const input, gboolean previous);
89 static char* _log_autocomplete(ProfWin* window, const char* const input, gboolean previous);
90 static char* _form_autocomplete(ProfWin* window, const char* const input, gboolean previous);
91 static char* _form_field_autocomplete(ProfWin* window, const char* const input, gboolean previous);
92 static char* _occupants_autocomplete(ProfWin* window, const char* const input, gboolean previous);
93 static char* _kick_autocomplete(ProfWin* window, const char* const input, gboolean previous);
94 static char* _ban_autocomplete(ProfWin* window, const char* const input, gboolean previous);
95 static char* _affiliation_autocomplete(ProfWin* window, const char* const input, gboolean previous);
96 static char* _role_autocomplete(ProfWin* window, const char* const input, gboolean previous);
97 static char* _resource_autocomplete(ProfWin* window, const char* const input, gboolean previous);
98 static char* _wintitle_autocomplete(ProfWin* window, const char* const input, gboolean previous);
99 static char* _inpblock_autocomplete(ProfWin* window, const char* const input, gboolean previous);
100 static char* _time_autocomplete(ProfWin* window, const char* const input, gboolean previous);
101 static char* _receipts_autocomplete(ProfWin* window, const char* const input, gboolean previous);
102 static char* _help_autocomplete(ProfWin* window, const char* const input, gboolean previous);
103 static char* _wins_autocomplete(ProfWin* window, const char* const input, gboolean previous);
104 static char* _tls_autocomplete(ProfWin* window, const char* const input, gboolean previous);
105 static char* _titlebar_autocomplete(ProfWin* window, const char* const input, gboolean previous);
106 static char* _script_autocomplete(ProfWin* window, const char* const input, gboolean previous);
107 static char* _subject_autocomplete(ProfWin* window, const char* const input, gboolean previous);
108 static char* _console_autocomplete(ProfWin* window, const char* const input, gboolean previous);
109 static char* _win_autocomplete(ProfWin* window, const char* const input, gboolean previous);
110 static char* _close_autocomplete(ProfWin* window, const char* const input, gboolean previous);
111 static char* _plugins_autocomplete(ProfWin* window, const char* const input, gboolean previous);
112 static char* _sendfile_autocomplete(ProfWin* window, const char* const input, gboolean previous);
113 static char* _blocked_autocomplete(ProfWin* window, const char* const input, gboolean previous);
114 static char* _tray_autocomplete(ProfWin* window, const char* const input, gboolean previous);
115 static char* _presence_autocomplete(ProfWin* window, const char* const input, gboolean previous);
116 static char* _rooms_autocomplete(ProfWin* window, const char* const input, gboolean previous);
117 static char* _statusbar_autocomplete(ProfWin* window, const char* const input, gboolean previous);
118 static char* _clear_autocomplete(ProfWin* window, const char* const input, gboolean previous);
119 static char* _invite_autocomplete(ProfWin* window, const char* const input, gboolean previous);
120 static char* _status_autocomplete(ProfWin* window, const char* const input, gboolean previous);
121 static char* _logging_autocomplete(ProfWin* window, const char* const input, gboolean previous);
122 static char* _color_autocomplete(ProfWin* window, const char* const input, gboolean previous);
123 static char* _avatar_autocomplete(ProfWin* window, const char* const input, gboolean previous);
124 static char* _correction_autocomplete(ProfWin* window, const char* const input, gboolean previous);
125 static char* _correct_autocomplete(ProfWin* window, const char* const input, gboolean previous);
126 static char* _software_autocomplete(ProfWin* window, const char* const input, gboolean previous);
127 static char* _url_autocomplete(ProfWin* window, const char* const input, gboolean previous);
128 static char* _executable_autocomplete(ProfWin* window, const char* const input, gboolean previous);
129 static char* _lastactivity_autocomplete(ProfWin* window, const char* const input, gboolean previous);
130 static char* _intype_autocomplete(ProfWin* window, const char* const input, gboolean previous);
131 
132 static char* _script_autocomplete_func(const char* const prefix, gboolean previous, void* context);
133 
134 static char* _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previous);
135 
136 static Autocomplete commands_ac;
137 static Autocomplete who_room_ac;
138 static Autocomplete who_roster_ac;
139 static Autocomplete help_ac;
140 static Autocomplete help_commands_ac;
141 static Autocomplete notify_ac;
142 static Autocomplete notify_chat_ac;
143 static Autocomplete notify_room_ac;
144 static Autocomplete notify_typing_ac;
145 static Autocomplete notify_mention_ac;
146 static Autocomplete notify_trigger_ac;
147 static Autocomplete prefs_ac;
148 static Autocomplete sub_ac;
149 static Autocomplete log_ac;
150 static Autocomplete autoaway_ac;
151 static Autocomplete autoaway_mode_ac;
152 static Autocomplete autoaway_presence_ac;
153 static Autocomplete autoconnect_ac;
154 static Autocomplete wintitle_ac;
155 static Autocomplete theme_ac;
156 static Autocomplete theme_load_ac;
157 static Autocomplete account_ac;
158 static Autocomplete account_set_ac;
159 static Autocomplete account_clear_ac;
160 static Autocomplete account_default_ac;
161 static Autocomplete account_status_ac;
162 static Autocomplete disco_ac;
163 static Autocomplete wins_ac;
164 static Autocomplete roster_ac;
165 static Autocomplete roster_show_ac;
166 static Autocomplete roster_by_ac;
167 static Autocomplete roster_count_ac;
168 static Autocomplete roster_order_ac;
169 static Autocomplete roster_header_ac;
170 static Autocomplete roster_contact_ac;
171 static Autocomplete roster_resource_ac;
172 static Autocomplete roster_presence_ac;
173 static Autocomplete roster_char_ac;
174 static Autocomplete roster_remove_all_ac;
175 static Autocomplete roster_room_ac;
176 static Autocomplete roster_room_show_ac;
177 static Autocomplete roster_room_use_ac;
178 static Autocomplete roster_room_position_ac;
179 static Autocomplete roster_room_by_ac;
180 static Autocomplete roster_room_order_ac;
181 static Autocomplete roster_unread_ac;
182 static Autocomplete roster_private_ac;
183 static Autocomplete group_ac;
184 static Autocomplete bookmark_ac;
185 static Autocomplete bookmark_property_ac;
186 static Autocomplete bookmark_ignore_ac;
187 #ifdef HAVE_LIBOTR
188 static Autocomplete otr_ac;
189 static Autocomplete otr_log_ac;
190 static Autocomplete otr_policy_ac;
191 static Autocomplete otr_sendfile_ac;
192 #endif
193 #ifdef HAVE_OMEMO
194 static Autocomplete omemo_ac;
195 static Autocomplete omemo_log_ac;
196 static Autocomplete omemo_policy_ac;
197 static Autocomplete omemo_trustmode_ac;
198 #endif
199 static Autocomplete connect_property_ac;
200 static Autocomplete tls_property_ac;
201 static Autocomplete auth_property_ac;
202 static Autocomplete alias_ac;
203 static Autocomplete aliases_ac;
204 static Autocomplete join_property_ac;
205 static Autocomplete room_ac;
206 static Autocomplete rooms_all_ac;
207 static Autocomplete rooms_list_ac;
208 static Autocomplete rooms_cache_ac;
209 static Autocomplete affiliation_ac;
210 static Autocomplete role_ac;
211 static Autocomplete affiliation_cmd_ac;
212 static Autocomplete role_cmd_ac;
213 static Autocomplete subject_ac;
214 static Autocomplete form_ac;
215 static Autocomplete form_field_multi_ac;
216 static Autocomplete occupants_ac;
217 static Autocomplete occupants_default_ac;
218 static Autocomplete occupants_show_ac;
219 static Autocomplete occupants_header_ac;
220 static Autocomplete occupants_header_char_ac;
221 static Autocomplete occupants_char_ac;
222 static Autocomplete time_ac;
223 static Autocomplete time_format_ac;
224 static Autocomplete resource_ac;
225 static Autocomplete inpblock_ac;
226 static Autocomplete receipts_ac;
227 #ifdef HAVE_LIBGPGME
228 static Autocomplete pgp_ac;
229 static Autocomplete pgp_log_ac;
230 static Autocomplete pgp_sendfile_ac;
231 static Autocomplete ox_ac;
232 static Autocomplete ox_log_ac;
233 static Autocomplete ox_sendfile_ac;
234 #endif
235 static Autocomplete tls_ac;
236 static Autocomplete titlebar_ac;
237 static Autocomplete titlebar_show_ac;
238 static Autocomplete tls_certpath_ac;
239 static Autocomplete script_ac;
240 static Autocomplete script_show_ac;
241 static Autocomplete console_ac;
242 static Autocomplete console_msg_ac;
243 static Autocomplete autoping_ac;
244 static Autocomplete plugins_ac;
245 static Autocomplete plugins_sourcepath_ac;
246 static Autocomplete plugins_load_ac;
247 static Autocomplete plugins_unload_ac;
248 static Autocomplete plugins_reload_ac;
249 static Autocomplete filepath_ac;
250 static Autocomplete blocked_ac;
251 static Autocomplete tray_ac;
252 static Autocomplete presence_ac;
253 static Autocomplete presence_setting_ac;
254 static Autocomplete winpos_ac;
255 static Autocomplete statusbar_ac;
256 static Autocomplete statusbar_self_ac;
257 static Autocomplete statusbar_chat_ac;
258 static Autocomplete statusbar_room_ac;
259 static Autocomplete statusbar_show_ac;
260 static Autocomplete clear_ac;
261 static Autocomplete invite_ac;
262 static Autocomplete status_ac;
263 static Autocomplete status_state_ac;
264 static Autocomplete logging_ac;
265 static Autocomplete logging_group_ac;
266 static Autocomplete color_ac;
267 static Autocomplete correction_ac;
268 static Autocomplete avatar_ac;
269 static Autocomplete url_ac;
270 static Autocomplete executable_ac;
271 static Autocomplete intype_ac;
272 
273 /*!
274  * \brief Initialization of auto completion for commands.
275  *
276  * This function implements the auto completion for profanity's commands.
277  *
278  */
279 
280 void
cmd_ac_init(void)281 cmd_ac_init(void)
282 {
283     commands_ac = autocomplete_new();
284     aliases_ac = autocomplete_new();
285 
286     help_ac = autocomplete_new();
287     autocomplete_add(help_ac, "commands");
288     autocomplete_add(help_ac, "navigation");
289     autocomplete_add(help_ac, "search_all");
290     autocomplete_add(help_ac, "search_any");
291 
292     help_commands_ac = autocomplete_new();
293     autocomplete_add(help_commands_ac, "chat");
294     autocomplete_add(help_commands_ac, "groupchat");
295     autocomplete_add(help_commands_ac, "roster");
296     autocomplete_add(help_commands_ac, "presence");
297     autocomplete_add(help_commands_ac, "discovery");
298     autocomplete_add(help_commands_ac, "connection");
299     autocomplete_add(help_commands_ac, "ui");
300     autocomplete_add(help_commands_ac, "plugins");
301 
302     prefs_ac = autocomplete_new();
303     autocomplete_add(prefs_ac, "ui");
304     autocomplete_add(prefs_ac, "desktop");
305     autocomplete_add(prefs_ac, "chat");
306     autocomplete_add(prefs_ac, "log");
307     autocomplete_add(prefs_ac, "conn");
308     autocomplete_add(prefs_ac, "presence");
309 #ifdef HAVE_LIBOTR
310     autocomplete_add(prefs_ac, "otr");
311 #endif
312 #ifdef HAVE_LIBGPGME
313     autocomplete_add(prefs_ac, "pgp");
314 #endif
315 #ifdef HAVE_OMEMO
316     autocomplete_add(prefs_ac, "omemo");
317 #endif
318 
319     notify_ac = autocomplete_new();
320     autocomplete_add(notify_ac, "chat");
321     autocomplete_add(notify_ac, "room");
322     autocomplete_add(notify_ac, "typing");
323     autocomplete_add(notify_ac, "remind");
324     autocomplete_add(notify_ac, "invite");
325     autocomplete_add(notify_ac, "sub");
326     autocomplete_add(notify_ac, "on");
327     autocomplete_add(notify_ac, "off");
328     autocomplete_add(notify_ac, "mention");
329     autocomplete_add(notify_ac, "trigger");
330     autocomplete_add(notify_ac, "reset");
331 
332     notify_chat_ac = autocomplete_new();
333     autocomplete_add(notify_chat_ac, "on");
334     autocomplete_add(notify_chat_ac, "off");
335     autocomplete_add(notify_chat_ac, "current");
336     autocomplete_add(notify_chat_ac, "text");
337 
338     notify_room_ac = autocomplete_new();
339     autocomplete_add(notify_room_ac, "on");
340     autocomplete_add(notify_room_ac, "off");
341     autocomplete_add(notify_room_ac, "mention");
342     autocomplete_add(notify_room_ac, "current");
343     autocomplete_add(notify_room_ac, "text");
344     autocomplete_add(notify_room_ac, "trigger");
345 
346     notify_typing_ac = autocomplete_new();
347     autocomplete_add(notify_typing_ac, "on");
348     autocomplete_add(notify_typing_ac, "off");
349     autocomplete_add(notify_typing_ac, "current");
350 
351     notify_mention_ac = autocomplete_new();
352     autocomplete_add(notify_mention_ac, "on");
353     autocomplete_add(notify_mention_ac, "off");
354     autocomplete_add(notify_mention_ac, "case_sensitive");
355     autocomplete_add(notify_mention_ac, "case_insensitive");
356     autocomplete_add(notify_mention_ac, "word_whole");
357     autocomplete_add(notify_mention_ac, "word_part");
358 
359     notify_trigger_ac = autocomplete_new();
360     autocomplete_add(notify_trigger_ac, "add");
361     autocomplete_add(notify_trigger_ac, "remove");
362     autocomplete_add(notify_trigger_ac, "list");
363     autocomplete_add(notify_trigger_ac, "on");
364     autocomplete_add(notify_trigger_ac, "off");
365 
366     sub_ac = autocomplete_new();
367     autocomplete_add(sub_ac, "request");
368     autocomplete_add(sub_ac, "allow");
369     autocomplete_add(sub_ac, "deny");
370     autocomplete_add(sub_ac, "show");
371     autocomplete_add(sub_ac, "sent");
372     autocomplete_add(sub_ac, "received");
373 
374     wintitle_ac = autocomplete_new();
375     autocomplete_add(wintitle_ac, "show");
376     autocomplete_add(wintitle_ac, "goodbye");
377 
378     log_ac = autocomplete_new();
379     autocomplete_add(log_ac, "maxsize");
380     autocomplete_add(log_ac, "rotate");
381     autocomplete_add(log_ac, "shared");
382     autocomplete_add(log_ac, "where");
383 
384     autoaway_ac = autocomplete_new();
385     autocomplete_add(autoaway_ac, "mode");
386     autocomplete_add(autoaway_ac, "time");
387     autocomplete_add(autoaway_ac, "message");
388     autocomplete_add(autoaway_ac, "check");
389 
390     autoaway_mode_ac = autocomplete_new();
391     autocomplete_add(autoaway_mode_ac, "away");
392     autocomplete_add(autoaway_mode_ac, "idle");
393     autocomplete_add(autoaway_mode_ac, "off");
394 
395     autoaway_presence_ac = autocomplete_new();
396     autocomplete_add(autoaway_presence_ac, "away");
397     autocomplete_add(autoaway_presence_ac, "xa");
398 
399     autoconnect_ac = autocomplete_new();
400     autocomplete_add(autoconnect_ac, "set");
401     autocomplete_add(autoconnect_ac, "off");
402 
403     theme_ac = autocomplete_new();
404     autocomplete_add(theme_ac, "load");
405     autocomplete_add(theme_ac, "full-load");
406     autocomplete_add(theme_ac, "list");
407     autocomplete_add(theme_ac, "colours");
408     autocomplete_add(theme_ac, "properties");
409 
410     disco_ac = autocomplete_new();
411     autocomplete_add(disco_ac, "info");
412     autocomplete_add(disco_ac, "items");
413 
414     account_ac = autocomplete_new();
415     autocomplete_add(account_ac, "list");
416     autocomplete_add(account_ac, "show");
417     autocomplete_add(account_ac, "add");
418     autocomplete_add(account_ac, "remove");
419     autocomplete_add(account_ac, "enable");
420     autocomplete_add(account_ac, "disable");
421     autocomplete_add(account_ac, "default");
422     autocomplete_add(account_ac, "rename");
423     autocomplete_add(account_ac, "set");
424     autocomplete_add(account_ac, "clear");
425 
426     account_set_ac = autocomplete_new();
427     autocomplete_add(account_set_ac, "jid");
428     autocomplete_add(account_set_ac, "server");
429     autocomplete_add(account_set_ac, "port");
430     autocomplete_add(account_set_ac, "status");
431     autocomplete_add(account_set_ac, "online");
432     autocomplete_add(account_set_ac, "chat");
433     autocomplete_add(account_set_ac, "away");
434     autocomplete_add(account_set_ac, "xa");
435     autocomplete_add(account_set_ac, "dnd");
436     autocomplete_add(account_set_ac, "resource");
437     autocomplete_add(account_set_ac, "password");
438     autocomplete_add(account_set_ac, "eval_password");
439     autocomplete_add(account_set_ac, "muc");
440     autocomplete_add(account_set_ac, "nick");
441     autocomplete_add(account_set_ac, "otr");
442     autocomplete_add(account_set_ac, "pgpkeyid");
443     autocomplete_add(account_set_ac, "startscript");
444     autocomplete_add(account_set_ac, "tls");
445     autocomplete_add(account_set_ac, "auth");
446     autocomplete_add(account_set_ac, "theme");
447 
448     account_clear_ac = autocomplete_new();
449     autocomplete_add(account_clear_ac, "password");
450     autocomplete_add(account_clear_ac, "eval_password");
451     autocomplete_add(account_clear_ac, "server");
452     autocomplete_add(account_clear_ac, "port");
453     autocomplete_add(account_clear_ac, "otr");
454     autocomplete_add(account_clear_ac, "pgpkeyid");
455     autocomplete_add(account_clear_ac, "startscript");
456     autocomplete_add(account_clear_ac, "theme");
457     autocomplete_add(account_clear_ac, "muc");
458     autocomplete_add(account_clear_ac, "resource");
459 
460     account_default_ac = autocomplete_new();
461     autocomplete_add(account_default_ac, "set");
462     autocomplete_add(account_default_ac, "off");
463 
464     account_status_ac = autocomplete_new();
465     autocomplete_add(account_status_ac, "online");
466     autocomplete_add(account_status_ac, "chat");
467     autocomplete_add(account_status_ac, "away");
468     autocomplete_add(account_status_ac, "xa");
469     autocomplete_add(account_status_ac, "dnd");
470     autocomplete_add(account_status_ac, "last");
471 
472     wins_ac = autocomplete_new();
473     autocomplete_add(wins_ac, "unread");
474     autocomplete_add(wins_ac, "attention");
475     autocomplete_add(wins_ac, "prune");
476     autocomplete_add(wins_ac, "swap");
477 
478     roster_ac = autocomplete_new();
479     autocomplete_add(roster_ac, "add");
480     autocomplete_add(roster_ac, "online");
481     autocomplete_add(roster_ac, "nick");
482     autocomplete_add(roster_ac, "clearnick");
483     autocomplete_add(roster_ac, "remove");
484     autocomplete_add(roster_ac, "remove_all");
485     autocomplete_add(roster_ac, "show");
486     autocomplete_add(roster_ac, "hide");
487     autocomplete_add(roster_ac, "by");
488     autocomplete_add(roster_ac, "count");
489     autocomplete_add(roster_ac, "color");
490     autocomplete_add(roster_ac, "order");
491     autocomplete_add(roster_ac, "unread");
492     autocomplete_add(roster_ac, "room");
493     autocomplete_add(roster_ac, "size");
494     autocomplete_add(roster_ac, "wrap");
495     autocomplete_add(roster_ac, "header");
496     autocomplete_add(roster_ac, "contact");
497     autocomplete_add(roster_ac, "resource");
498     autocomplete_add(roster_ac, "presence");
499     autocomplete_add(roster_ac, "private");
500     autocomplete_add(roster_ac, "group");
501 
502     roster_private_ac = autocomplete_new();
503     autocomplete_add(roster_private_ac, "room");
504     autocomplete_add(roster_private_ac, "group");
505     autocomplete_add(roster_private_ac, "off");
506     autocomplete_add(roster_private_ac, "char");
507 
508     roster_header_ac = autocomplete_new();
509     autocomplete_add(roster_header_ac, "char");
510 
511     roster_contact_ac = autocomplete_new();
512     autocomplete_add(roster_contact_ac, "char");
513     autocomplete_add(roster_contact_ac, "indent");
514 
515     roster_resource_ac = autocomplete_new();
516     autocomplete_add(roster_resource_ac, "char");
517     autocomplete_add(roster_resource_ac, "indent");
518     autocomplete_add(roster_resource_ac, "join");
519 
520     roster_presence_ac = autocomplete_new();
521     autocomplete_add(roster_presence_ac, "indent");
522 
523     roster_char_ac = autocomplete_new();
524     autocomplete_add(roster_char_ac, "none");
525 
526     roster_show_ac = autocomplete_new();
527     autocomplete_add(roster_show_ac, "offline");
528     autocomplete_add(roster_show_ac, "resource");
529     autocomplete_add(roster_show_ac, "presence");
530     autocomplete_add(roster_show_ac, "status");
531     autocomplete_add(roster_show_ac, "empty");
532     autocomplete_add(roster_show_ac, "priority");
533     autocomplete_add(roster_show_ac, "contacts");
534     autocomplete_add(roster_show_ac, "unsubscribed");
535     autocomplete_add(roster_show_ac, "rooms");
536 
537     roster_by_ac = autocomplete_new();
538     autocomplete_add(roster_by_ac, "group");
539     autocomplete_add(roster_by_ac, "presence");
540     autocomplete_add(roster_by_ac, "none");
541 
542     roster_count_ac = autocomplete_new();
543     autocomplete_add(roster_count_ac, "unread");
544     autocomplete_add(roster_count_ac, "items");
545     autocomplete_add(roster_count_ac, "off");
546     autocomplete_add(roster_count_ac, "zero");
547 
548     roster_order_ac = autocomplete_new();
549     autocomplete_add(roster_order_ac, "name");
550     autocomplete_add(roster_order_ac, "presence");
551 
552     roster_unread_ac = autocomplete_new();
553     autocomplete_add(roster_unread_ac, "before");
554     autocomplete_add(roster_unread_ac, "after");
555     autocomplete_add(roster_unread_ac, "off");
556 
557     roster_room_ac = autocomplete_new();
558     autocomplete_add(roster_room_ac, "char");
559     autocomplete_add(roster_room_ac, "position");
560     autocomplete_add(roster_room_ac, "by");
561     autocomplete_add(roster_room_ac, "order");
562     autocomplete_add(roster_room_ac, "unread");
563     autocomplete_add(roster_room_ac, "private");
564     autocomplete_add(roster_room_ac, "show");
565     autocomplete_add(roster_room_ac, "hide");
566     autocomplete_add(roster_room_ac, "use");
567 
568     roster_room_show_ac = autocomplete_new();
569     autocomplete_add(roster_room_show_ac, "server");
570 
571     roster_room_by_ac = autocomplete_new();
572     autocomplete_add(roster_room_by_ac, "service");
573     autocomplete_add(roster_room_by_ac, "none");
574 
575     roster_room_use_ac = autocomplete_new();
576     autocomplete_add(roster_room_use_ac, "jid");
577     autocomplete_add(roster_room_use_ac, "name");
578 
579     roster_room_order_ac = autocomplete_new();
580     autocomplete_add(roster_room_order_ac, "name");
581     autocomplete_add(roster_room_order_ac, "unread");
582 
583     roster_room_position_ac = autocomplete_new();
584     autocomplete_add(roster_room_position_ac, "first");
585     autocomplete_add(roster_room_position_ac, "last");
586 
587     roster_remove_all_ac = autocomplete_new();
588     autocomplete_add(roster_remove_all_ac, "contacts");
589 
590     group_ac = autocomplete_new();
591     autocomplete_add(group_ac, "show");
592     autocomplete_add(group_ac, "add");
593     autocomplete_add(group_ac, "remove");
594 
595     theme_load_ac = NULL;
596     plugins_load_ac = NULL;
597     plugins_unload_ac = NULL;
598     plugins_reload_ac = NULL;
599 
600     who_roster_ac = autocomplete_new();
601     autocomplete_add(who_roster_ac, "chat");
602     autocomplete_add(who_roster_ac, "online");
603     autocomplete_add(who_roster_ac, "away");
604     autocomplete_add(who_roster_ac, "xa");
605     autocomplete_add(who_roster_ac, "dnd");
606     autocomplete_add(who_roster_ac, "offline");
607     autocomplete_add(who_roster_ac, "available");
608     autocomplete_add(who_roster_ac, "unavailable");
609     autocomplete_add(who_roster_ac, "any");
610 
611     who_room_ac = autocomplete_new();
612     autocomplete_add(who_room_ac, "chat");
613     autocomplete_add(who_room_ac, "online");
614     autocomplete_add(who_room_ac, "away");
615     autocomplete_add(who_room_ac, "xa");
616     autocomplete_add(who_room_ac, "dnd");
617     autocomplete_add(who_room_ac, "available");
618     autocomplete_add(who_room_ac, "unavailable");
619     autocomplete_add(who_room_ac, "moderator");
620     autocomplete_add(who_room_ac, "participant");
621     autocomplete_add(who_room_ac, "visitor");
622     autocomplete_add(who_room_ac, "owner");
623     autocomplete_add(who_room_ac, "admin");
624     autocomplete_add(who_room_ac, "member");
625 
626     bookmark_ac = autocomplete_new();
627     autocomplete_add(bookmark_ac, "list");
628     autocomplete_add(bookmark_ac, "add");
629     autocomplete_add(bookmark_ac, "update");
630     autocomplete_add(bookmark_ac, "remove");
631     autocomplete_add(bookmark_ac, "join");
632     autocomplete_add(bookmark_ac, "invites");
633     autocomplete_add(bookmark_ac, "ignore");
634 
635     bookmark_property_ac = autocomplete_new();
636     autocomplete_add(bookmark_property_ac, "nick");
637     autocomplete_add(bookmark_property_ac, "password");
638     autocomplete_add(bookmark_property_ac, "autojoin");
639     autocomplete_add(bookmark_property_ac, "name");
640 
641     bookmark_ignore_ac = autocomplete_new();
642     autocomplete_add(bookmark_ignore_ac, "add");
643     autocomplete_add(bookmark_ignore_ac, "remove");
644 
645 #ifdef HAVE_LIBOTR
646     otr_ac = autocomplete_new();
647     autocomplete_add(otr_ac, "gen");
648     autocomplete_add(otr_ac, "start");
649     autocomplete_add(otr_ac, "end");
650     autocomplete_add(otr_ac, "myfp");
651     autocomplete_add(otr_ac, "theirfp");
652     autocomplete_add(otr_ac, "trust");
653     autocomplete_add(otr_ac, "untrust");
654     autocomplete_add(otr_ac, "secret");
655     autocomplete_add(otr_ac, "log");
656     autocomplete_add(otr_ac, "libver");
657     autocomplete_add(otr_ac, "policy");
658     autocomplete_add(otr_ac, "question");
659     autocomplete_add(otr_ac, "answer");
660     autocomplete_add(otr_ac, "char");
661     autocomplete_add(otr_ac, "sendfile");
662 
663     otr_log_ac = autocomplete_new();
664     autocomplete_add(otr_log_ac, "on");
665     autocomplete_add(otr_log_ac, "off");
666     autocomplete_add(otr_log_ac, "redact");
667 
668     otr_policy_ac = autocomplete_new();
669     autocomplete_add(otr_policy_ac, "manual");
670     autocomplete_add(otr_policy_ac, "opportunistic");
671     autocomplete_add(otr_policy_ac, "always");
672 
673     otr_sendfile_ac = autocomplete_new();
674     autocomplete_add(otr_sendfile_ac, "on");
675     autocomplete_add(otr_sendfile_ac, "off");
676 #endif
677 
678 #ifdef HAVE_OMEMO
679     omemo_ac = autocomplete_new();
680     autocomplete_add(omemo_ac, "gen");
681     autocomplete_add(omemo_ac, "log");
682     autocomplete_add(omemo_ac, "start");
683     autocomplete_add(omemo_ac, "end");
684     autocomplete_add(omemo_ac, "trust");
685     autocomplete_add(omemo_ac, "untrust");
686     autocomplete_add(omemo_ac, "fingerprint");
687     autocomplete_add(omemo_ac, "clear_device_list");
688     autocomplete_add(omemo_ac, "policy");
689     autocomplete_add(omemo_ac, "trustmode");
690     autocomplete_add(omemo_ac, "char");
691 
692     omemo_log_ac = autocomplete_new();
693     autocomplete_add(omemo_log_ac, "on");
694     autocomplete_add(omemo_log_ac, "off");
695     autocomplete_add(omemo_log_ac, "redact");
696 
697     omemo_policy_ac = autocomplete_new();
698     autocomplete_add(omemo_policy_ac, "manual");
699     autocomplete_add(omemo_policy_ac, "automatic");
700     autocomplete_add(omemo_policy_ac, "always");
701 
702     // Autocomplete OMEMO trustmode
703     omemo_trustmode_ac = autocomplete_new();
704     autocomplete_add(omemo_trustmode_ac, "manual");
705     autocomplete_add(omemo_trustmode_ac, "firstusage");
706     autocomplete_add(omemo_trustmode_ac, "blind");
707 #endif
708 
709     connect_property_ac = autocomplete_new();
710     autocomplete_add(connect_property_ac, "auth");
711     autocomplete_add(connect_property_ac, "server");
712     autocomplete_add(connect_property_ac, "port");
713     autocomplete_add(connect_property_ac, "tls");
714 
715     tls_property_ac = autocomplete_new();
716     autocomplete_add(tls_property_ac, "force");
717     autocomplete_add(tls_property_ac, "allow");
718     autocomplete_add(tls_property_ac, "trust");
719     autocomplete_add(tls_property_ac, "legacy");
720     autocomplete_add(tls_property_ac, "disable");
721 
722     auth_property_ac = autocomplete_new();
723     autocomplete_add(auth_property_ac, "default");
724     autocomplete_add(auth_property_ac, "legacy");
725 
726     join_property_ac = autocomplete_new();
727     autocomplete_add(join_property_ac, "nick");
728     autocomplete_add(join_property_ac, "password");
729 
730     alias_ac = autocomplete_new();
731     autocomplete_add(alias_ac, "add");
732     autocomplete_add(alias_ac, "remove");
733     autocomplete_add(alias_ac, "list");
734 
735     room_ac = autocomplete_new();
736     autocomplete_add(room_ac, "accept");
737     autocomplete_add(room_ac, "destroy");
738     autocomplete_add(room_ac, "config");
739 
740     rooms_all_ac = autocomplete_new();
741     autocomplete_add(rooms_all_ac, "service");
742     autocomplete_add(rooms_all_ac, "filter");
743     autocomplete_add(rooms_all_ac, "cache");
744 
745     rooms_list_ac = autocomplete_new();
746     autocomplete_add(rooms_list_ac, "service");
747     autocomplete_add(rooms_list_ac, "filter");
748 
749     rooms_cache_ac = autocomplete_new();
750     autocomplete_add(rooms_cache_ac, "on");
751     autocomplete_add(rooms_cache_ac, "off");
752     autocomplete_add(rooms_cache_ac, "clear");
753 
754     affiliation_ac = autocomplete_new();
755     autocomplete_add(affiliation_ac, "owner");
756     autocomplete_add(affiliation_ac, "admin");
757     autocomplete_add(affiliation_ac, "member");
758     autocomplete_add(affiliation_ac, "none");
759     autocomplete_add(affiliation_ac, "outcast");
760 
761     role_ac = autocomplete_new();
762     autocomplete_add(role_ac, "moderator");
763     autocomplete_add(role_ac, "participant");
764     autocomplete_add(role_ac, "visitor");
765     autocomplete_add(role_ac, "none");
766 
767     affiliation_cmd_ac = autocomplete_new();
768     autocomplete_add(affiliation_cmd_ac, "list");
769     autocomplete_add(affiliation_cmd_ac, "request");
770     autocomplete_add(affiliation_cmd_ac, "register");
771     autocomplete_add(affiliation_cmd_ac, "set");
772 
773     role_cmd_ac = autocomplete_new();
774     autocomplete_add(role_cmd_ac, "list");
775     autocomplete_add(role_cmd_ac, "set");
776 
777     subject_ac = autocomplete_new();
778     autocomplete_add(subject_ac, "set");
779     autocomplete_add(subject_ac, "edit");
780     autocomplete_add(subject_ac, "prepend");
781     autocomplete_add(subject_ac, "append");
782     autocomplete_add(subject_ac, "clear");
783 
784     form_ac = autocomplete_new();
785     autocomplete_add(form_ac, "submit");
786     autocomplete_add(form_ac, "cancel");
787     autocomplete_add(form_ac, "show");
788     autocomplete_add(form_ac, "help");
789 
790     form_field_multi_ac = autocomplete_new();
791     autocomplete_add(form_field_multi_ac, "add");
792     autocomplete_add(form_field_multi_ac, "remove");
793 
794     occupants_ac = autocomplete_new();
795     autocomplete_add(occupants_ac, "show");
796     autocomplete_add(occupants_ac, "hide");
797     autocomplete_add(occupants_ac, "default");
798     autocomplete_add(occupants_ac, "size");
799     autocomplete_add(occupants_ac, "indent");
800     autocomplete_add(occupants_ac, "header");
801     autocomplete_add(occupants_ac, "wrap");
802     autocomplete_add(occupants_ac, "char");
803     autocomplete_add(occupants_ac, "color");
804 
805     occupants_default_ac = autocomplete_new();
806     autocomplete_add(occupants_default_ac, "show");
807     autocomplete_add(occupants_default_ac, "hide");
808 
809     occupants_show_ac = autocomplete_new();
810     autocomplete_add(occupants_show_ac, "jid");
811     autocomplete_add(occupants_show_ac, "offline");
812 
813     occupants_char_ac = autocomplete_new();
814     autocomplete_add(occupants_char_ac, "none");
815 
816     occupants_header_ac = autocomplete_new();
817     autocomplete_add(occupants_header_ac, "char");
818 
819     occupants_header_char_ac = autocomplete_new();
820     autocomplete_add(occupants_header_char_ac, "none");
821 
822     time_ac = autocomplete_new();
823     autocomplete_add(time_ac, "console");
824     autocomplete_add(time_ac, "chat");
825     autocomplete_add(time_ac, "muc");
826     autocomplete_add(time_ac, "config");
827     autocomplete_add(time_ac, "private");
828     autocomplete_add(time_ac, "xml");
829     autocomplete_add(time_ac, "statusbar");
830     autocomplete_add(time_ac, "lastactivity");
831     autocomplete_add(time_ac, "all");
832 
833     time_format_ac = autocomplete_new();
834     autocomplete_add(time_format_ac, "set");
835     autocomplete_add(time_format_ac, "off");
836 
837     resource_ac = autocomplete_new();
838     autocomplete_add(resource_ac, "set");
839     autocomplete_add(resource_ac, "off");
840     autocomplete_add(resource_ac, "title");
841     autocomplete_add(resource_ac, "message");
842 
843     inpblock_ac = autocomplete_new();
844     autocomplete_add(inpblock_ac, "timeout");
845     autocomplete_add(inpblock_ac, "dynamic");
846 
847     receipts_ac = autocomplete_new();
848     autocomplete_add(receipts_ac, "send");
849     autocomplete_add(receipts_ac, "request");
850 
851 #ifdef HAVE_LIBGPGME
852     pgp_ac = autocomplete_new();
853     autocomplete_add(pgp_ac, "keys");
854     autocomplete_add(pgp_ac, "contacts");
855     autocomplete_add(pgp_ac, "setkey");
856     autocomplete_add(pgp_ac, "libver");
857     autocomplete_add(pgp_ac, "start");
858     autocomplete_add(pgp_ac, "end");
859     autocomplete_add(pgp_ac, "log");
860     autocomplete_add(pgp_ac, "char");
861     autocomplete_add(pgp_ac, "sendfile");
862 
863     pgp_log_ac = autocomplete_new();
864     autocomplete_add(pgp_log_ac, "on");
865     autocomplete_add(pgp_log_ac, "off");
866     autocomplete_add(pgp_log_ac, "redact");
867 
868     pgp_sendfile_ac = autocomplete_new();
869     autocomplete_add(pgp_sendfile_ac, "on");
870     autocomplete_add(pgp_sendfile_ac, "off");
871 
872     // XEP-0373: OX
873     ox_ac = autocomplete_new();
874     autocomplete_add(ox_ac, "keys");
875     autocomplete_add(ox_ac, "contacts");
876     autocomplete_add(ox_ac, "start");
877     autocomplete_add(ox_ac, "end");
878     autocomplete_add(ox_ac, "log");
879     autocomplete_add(ox_ac, "char");
880     autocomplete_add(ox_ac, "sendfile");
881     autocomplete_add(ox_ac, "announce");
882     autocomplete_add(ox_ac, "discover");
883     autocomplete_add(ox_ac, "request");
884 #endif
885 
886     tls_ac = autocomplete_new();
887     autocomplete_add(tls_ac, "allow");
888     autocomplete_add(tls_ac, "always");
889     autocomplete_add(tls_ac, "deny");
890     autocomplete_add(tls_ac, "cert");
891     autocomplete_add(tls_ac, "trust");
892     autocomplete_add(tls_ac, "trusted");
893     autocomplete_add(tls_ac, "revoke");
894     autocomplete_add(tls_ac, "certpath");
895 
896     titlebar_ac = autocomplete_new();
897     autocomplete_add(titlebar_ac, "up");
898     autocomplete_add(titlebar_ac, "down");
899     autocomplete_add(titlebar_ac, "show");
900     autocomplete_add(titlebar_ac, "hide");
901 
902     titlebar_show_ac = autocomplete_new();
903     autocomplete_add(titlebar_show_ac, "tls");
904     autocomplete_add(titlebar_show_ac, "encwarn");
905     autocomplete_add(titlebar_show_ac, "resource");
906     autocomplete_add(titlebar_show_ac, "presence");
907     autocomplete_add(titlebar_show_ac, "jid");
908     autocomplete_add(titlebar_show_ac, "name");
909 
910     tls_certpath_ac = autocomplete_new();
911     autocomplete_add(tls_certpath_ac, "set");
912     autocomplete_add(tls_certpath_ac, "clear");
913     autocomplete_add(tls_certpath_ac, "default");
914 
915     script_ac = autocomplete_new();
916     autocomplete_add(script_ac, "run");
917     autocomplete_add(script_ac, "list");
918     autocomplete_add(script_ac, "show");
919 
920     script_show_ac = NULL;
921 
922     console_ac = autocomplete_new();
923     autocomplete_add(console_ac, "chat");
924     autocomplete_add(console_ac, "muc");
925     autocomplete_add(console_ac, "private");
926 
927     console_msg_ac = autocomplete_new();
928     autocomplete_add(console_msg_ac, "all");
929     autocomplete_add(console_msg_ac, "first");
930     autocomplete_add(console_msg_ac, "mention");
931     autocomplete_add(console_msg_ac, "none");
932 
933     autoping_ac = autocomplete_new();
934     autocomplete_add(autoping_ac, "set");
935     autocomplete_add(autoping_ac, "timeout");
936 
937     plugins_ac = autocomplete_new();
938     autocomplete_add(plugins_ac, "install");
939     autocomplete_add(plugins_ac, "load");
940     autocomplete_add(plugins_ac, "unload");
941     autocomplete_add(plugins_ac, "reload");
942     autocomplete_add(plugins_ac, "python_version");
943     autocomplete_add(plugins_ac, "sourcepath");
944 
945     plugins_sourcepath_ac = autocomplete_new();
946     autocomplete_add(plugins_sourcepath_ac, "set");
947     autocomplete_add(plugins_sourcepath_ac, "clear");
948 
949     filepath_ac = autocomplete_new();
950 
951     blocked_ac = autocomplete_new();
952     autocomplete_add(blocked_ac, "add");
953     autocomplete_add(blocked_ac, "remove");
954     autocomplete_add(blocked_ac, "report-abuse");
955     autocomplete_add(blocked_ac, "report-spam");
956 
957     clear_ac = autocomplete_new();
958     autocomplete_add(clear_ac, "persist_history");
959 
960     tray_ac = autocomplete_new();
961     autocomplete_add(tray_ac, "on");
962     autocomplete_add(tray_ac, "off");
963     autocomplete_add(tray_ac, "read");
964     autocomplete_add(tray_ac, "timer");
965 
966     presence_ac = autocomplete_new();
967     autocomplete_add(presence_ac, "titlebar");
968     autocomplete_add(presence_ac, "console");
969     autocomplete_add(presence_ac, "chat");
970     autocomplete_add(presence_ac, "room");
971 
972     presence_setting_ac = autocomplete_new();
973     autocomplete_add(presence_setting_ac, "all");
974     autocomplete_add(presence_setting_ac, "online");
975     autocomplete_add(presence_setting_ac, "none");
976 
977     winpos_ac = autocomplete_new();
978     autocomplete_add(winpos_ac, "up");
979     autocomplete_add(winpos_ac, "down");
980 
981     statusbar_ac = autocomplete_new();
982     autocomplete_add(statusbar_ac, "up");
983     autocomplete_add(statusbar_ac, "down");
984     autocomplete_add(statusbar_ac, "show");
985     autocomplete_add(statusbar_ac, "hide");
986     autocomplete_add(statusbar_ac, "maxtabs");
987     autocomplete_add(statusbar_ac, "tablen");
988     autocomplete_add(statusbar_ac, "self");
989     autocomplete_add(statusbar_ac, "chat");
990     autocomplete_add(statusbar_ac, "room");
991 
992     invite_ac = autocomplete_new();
993     autocomplete_add(invite_ac, "send");
994     autocomplete_add(invite_ac, "list");
995     autocomplete_add(invite_ac, "decline");
996 
997     statusbar_self_ac = autocomplete_new();
998     autocomplete_add(statusbar_self_ac, "user");
999     autocomplete_add(statusbar_self_ac, "barejid");
1000     autocomplete_add(statusbar_self_ac, "fulljid");
1001     autocomplete_add(statusbar_self_ac, "off");
1002 
1003     statusbar_chat_ac = autocomplete_new();
1004     autocomplete_add(statusbar_chat_ac, "user");
1005     autocomplete_add(statusbar_chat_ac, "jid");
1006 
1007     statusbar_room_ac = autocomplete_new();
1008     autocomplete_add(statusbar_room_ac, "room");
1009     autocomplete_add(statusbar_room_ac, "jid");
1010 
1011     statusbar_show_ac = autocomplete_new();
1012     autocomplete_add(statusbar_show_ac, "name");
1013     autocomplete_add(statusbar_show_ac, "number");
1014     autocomplete_add(statusbar_show_ac, "read");
1015 
1016     status_ac = autocomplete_new();
1017     autocomplete_add(status_ac, "set");
1018     autocomplete_add(status_ac, "get");
1019 
1020     status_state_ac = autocomplete_new();
1021     autocomplete_add(status_state_ac, "online");
1022     autocomplete_add(status_state_ac, "chat");
1023     autocomplete_add(status_state_ac, "away");
1024     autocomplete_add(status_state_ac, "xa");
1025     autocomplete_add(status_state_ac, "dnd");
1026 
1027     logging_ac = autocomplete_new();
1028     autocomplete_add(logging_ac, "chat");
1029     autocomplete_add(logging_ac, "group");
1030 
1031     logging_group_ac = autocomplete_new();
1032     autocomplete_add(logging_group_ac, "on");
1033     autocomplete_add(logging_group_ac, "off");
1034     autocomplete_add(logging_group_ac, "color");
1035 
1036     color_ac = autocomplete_new();
1037     autocomplete_add(color_ac, "on");
1038     autocomplete_add(color_ac, "off");
1039     autocomplete_add(color_ac, "redgreen");
1040     autocomplete_add(color_ac, "blue");
1041     autocomplete_add(color_ac, "own");
1042 
1043     correction_ac = autocomplete_new();
1044     autocomplete_add(correction_ac, "on");
1045     autocomplete_add(correction_ac, "off");
1046     autocomplete_add(correction_ac, "char");
1047 
1048     avatar_ac = autocomplete_new();
1049     autocomplete_add(avatar_ac, "get");
1050     autocomplete_add(avatar_ac, "open");
1051 
1052     url_ac = autocomplete_new();
1053     autocomplete_add(url_ac, "open");
1054     autocomplete_add(url_ac, "save");
1055 
1056     executable_ac = autocomplete_new();
1057     autocomplete_add(executable_ac, "avatar");
1058     autocomplete_add(executable_ac, "urlopen");
1059     autocomplete_add(executable_ac, "urlsave");
1060     autocomplete_add(executable_ac, "editor");
1061 
1062     intype_ac = autocomplete_new();
1063     autocomplete_add(intype_ac, "console");
1064     autocomplete_add(intype_ac, "titlebar");
1065 }
1066 
1067 void
cmd_ac_add(const char * const value)1068 cmd_ac_add(const char* const value)
1069 {
1070     if (commands_ac == NULL) {
1071         return;
1072     }
1073 
1074     autocomplete_add(commands_ac, value);
1075 }
1076 
1077 void
cmd_ac_add_help(const char * const value)1078 cmd_ac_add_help(const char* const value)
1079 {
1080     if (help_ac == NULL) {
1081         return;
1082     }
1083 
1084     autocomplete_add(help_ac, value);
1085 }
1086 
1087 void
cmd_ac_add_cmd(Command * command)1088 cmd_ac_add_cmd(Command* command)
1089 {
1090     autocomplete_add(commands_ac, command->cmd);
1091     autocomplete_add(help_ac, command->cmd + 1);
1092 }
1093 
1094 void
cmd_ac_add_alias(ProfAlias * alias)1095 cmd_ac_add_alias(ProfAlias* alias)
1096 {
1097     GString* ac_alias = g_string_new("/");
1098     g_string_append(ac_alias, alias->name);
1099     autocomplete_add(commands_ac, ac_alias->str);
1100     autocomplete_add(aliases_ac, alias->name);
1101     g_string_free(ac_alias, TRUE);
1102 }
1103 
1104 void
cmd_ac_add_alias_value(char * value)1105 cmd_ac_add_alias_value(char* value)
1106 {
1107     if (aliases_ac == NULL) {
1108         return;
1109     }
1110 
1111     autocomplete_add(aliases_ac, value);
1112 }
1113 
1114 void
cmd_ac_remove_alias_value(char * value)1115 cmd_ac_remove_alias_value(char* value)
1116 {
1117     if (aliases_ac == NULL) {
1118         return;
1119     }
1120     autocomplete_remove(aliases_ac, value);
1121 }
1122 
1123 void
cmd_ac_remove(const char * const value)1124 cmd_ac_remove(const char* const value)
1125 {
1126     if (commands_ac == NULL) {
1127         return;
1128     }
1129 
1130     autocomplete_remove(commands_ac, value);
1131 }
1132 
1133 void
cmd_ac_remove_help(const char * const value)1134 cmd_ac_remove_help(const char* const value)
1135 {
1136     if (help_ac == NULL) {
1137         return;
1138     }
1139 
1140     autocomplete_remove(help_ac, value);
1141 }
1142 
1143 gboolean
cmd_ac_exists(char * cmd)1144 cmd_ac_exists(char* cmd)
1145 {
1146     if (commands_ac == NULL) {
1147         return FALSE;
1148     }
1149 
1150     return autocomplete_contains(commands_ac, cmd);
1151 }
1152 
1153 void
cmd_ac_add_form_fields(DataForm * form)1154 cmd_ac_add_form_fields(DataForm* form)
1155 {
1156     if (form == NULL) {
1157         return;
1158     }
1159 
1160     GList* fields = autocomplete_create_list(form->tag_ac);
1161     GList* curr_field = fields;
1162     while (curr_field) {
1163         GString* field_str = g_string_new("/");
1164         g_string_append(field_str, curr_field->data);
1165         cmd_ac_add(field_str->str);
1166         g_string_free(field_str, TRUE);
1167         curr_field = g_list_next(curr_field);
1168     }
1169     g_list_free_full(fields, free);
1170 }
1171 
1172 void
cmd_ac_remove_form_fields(DataForm * form)1173 cmd_ac_remove_form_fields(DataForm* form)
1174 {
1175     if (form == NULL) {
1176         return;
1177     }
1178 
1179     GList* fields = autocomplete_create_list(form->tag_ac);
1180     GList* curr_field = fields;
1181     while (curr_field) {
1182         GString* field_str = g_string_new("/");
1183         g_string_append(field_str, curr_field->data);
1184         cmd_ac_remove(field_str->str);
1185         g_string_free(field_str, TRUE);
1186         curr_field = g_list_next(curr_field);
1187     }
1188     g_list_free_full(fields, free);
1189 }
1190 
1191 char*
cmd_ac_complete(ProfWin * window,const char * const input,gboolean previous)1192 cmd_ac_complete(ProfWin* window, const char* const input, gboolean previous)
1193 {
1194     char* found = NULL;
1195     // autocomplete command
1196     if ((strncmp(input, "/", 1) == 0) && (!strchr(input, ' '))) {
1197         found = autocomplete_complete(commands_ac, input, TRUE, previous);
1198 
1199         // autocomplete parameters
1200     } else {
1201         found = _cmd_ac_complete_params(window, input, previous);
1202     }
1203 
1204     return found;
1205 }
1206 
1207 void
cmd_ac_reset(ProfWin * window)1208 cmd_ac_reset(ProfWin* window)
1209 {
1210     jabber_conn_status_t conn_status = connection_get_status();
1211     if (conn_status == JABBER_CONNECTED) {
1212         roster_reset_search_attempts();
1213 
1214         if (window->type == WIN_CHAT) {
1215             ProfChatWin* chatwin = (ProfChatWin*)window;
1216             assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
1217             PContact contact = roster_get_contact(chatwin->barejid);
1218             if (contact) {
1219                 p_contact_resource_ac_reset(contact);
1220             }
1221         }
1222     }
1223 
1224     muc_invites_reset_ac();
1225     muc_confserver_reset_ac();
1226     accounts_reset_all_search();
1227     accounts_reset_enabled_search();
1228     tlscerts_reset_ac();
1229     prefs_reset_boolean_choice();
1230     presence_reset_sub_request_search();
1231 #ifdef HAVE_LIBGPGME
1232     p_gpg_autocomplete_key_reset();
1233 #endif
1234 #ifdef HAVE_OMEMO
1235     omemo_fingerprint_autocomplete_reset();
1236 #endif
1237     autocomplete_reset(help_ac);
1238     autocomplete_reset(help_commands_ac);
1239     autocomplete_reset(notify_ac);
1240     autocomplete_reset(notify_chat_ac);
1241     autocomplete_reset(notify_room_ac);
1242     autocomplete_reset(notify_typing_ac);
1243     autocomplete_reset(notify_mention_ac);
1244     autocomplete_reset(notify_trigger_ac);
1245     autocomplete_reset(sub_ac);
1246     autocomplete_reset(filepath_ac);
1247 
1248     autocomplete_reset(who_room_ac);
1249     autocomplete_reset(who_roster_ac);
1250     autocomplete_reset(prefs_ac);
1251     autocomplete_reset(log_ac);
1252     autocomplete_reset(commands_ac);
1253     autocomplete_reset(autoaway_ac);
1254     autocomplete_reset(autoaway_mode_ac);
1255     autocomplete_reset(autoaway_presence_ac);
1256     autocomplete_reset(autoconnect_ac);
1257     autocomplete_reset(theme_ac);
1258     if (theme_load_ac) {
1259         autocomplete_free(theme_load_ac);
1260         theme_load_ac = NULL;
1261     }
1262     if (plugins_load_ac) {
1263         autocomplete_free(plugins_load_ac);
1264         plugins_load_ac = NULL;
1265     }
1266     if (plugins_unload_ac) {
1267         autocomplete_free(plugins_unload_ac);
1268         plugins_unload_ac = NULL;
1269     }
1270     if (plugins_reload_ac) {
1271         autocomplete_free(plugins_reload_ac);
1272         plugins_reload_ac = NULL;
1273     }
1274     autocomplete_reset(account_ac);
1275     autocomplete_reset(account_set_ac);
1276     autocomplete_reset(account_clear_ac);
1277     autocomplete_reset(account_default_ac);
1278     autocomplete_reset(account_status_ac);
1279     autocomplete_reset(disco_ac);
1280     autocomplete_reset(wins_ac);
1281     autocomplete_reset(roster_ac);
1282     autocomplete_reset(roster_header_ac);
1283     autocomplete_reset(roster_contact_ac);
1284     autocomplete_reset(roster_resource_ac);
1285     autocomplete_reset(roster_presence_ac);
1286     autocomplete_reset(roster_char_ac);
1287     autocomplete_reset(roster_show_ac);
1288     autocomplete_reset(roster_by_ac);
1289     autocomplete_reset(roster_count_ac);
1290     autocomplete_reset(roster_order_ac);
1291     autocomplete_reset(roster_room_ac);
1292     autocomplete_reset(roster_room_show_ac);
1293     autocomplete_reset(roster_room_use_ac);
1294     autocomplete_reset(roster_room_by_ac);
1295     autocomplete_reset(roster_unread_ac);
1296     autocomplete_reset(roster_room_position_ac);
1297     autocomplete_reset(roster_room_order_ac);
1298     autocomplete_reset(roster_remove_all_ac);
1299     autocomplete_reset(roster_private_ac);
1300     autocomplete_reset(group_ac);
1301     autocomplete_reset(wintitle_ac);
1302     autocomplete_reset(bookmark_ac);
1303     autocomplete_reset(bookmark_property_ac);
1304     autocomplete_reset(bookmark_ignore_ac);
1305 #ifdef HAVE_LIBOTR
1306     autocomplete_reset(otr_ac);
1307     autocomplete_reset(otr_log_ac);
1308     autocomplete_reset(otr_policy_ac);
1309     autocomplete_reset(otr_sendfile_ac);
1310 #endif
1311 #ifdef HAVE_OMEMO
1312     autocomplete_reset(omemo_ac);
1313     autocomplete_reset(omemo_log_ac);
1314     autocomplete_reset(omemo_policy_ac);
1315     autocomplete_reset(omemo_trustmode_ac);
1316 #endif
1317     autocomplete_reset(connect_property_ac);
1318     autocomplete_reset(tls_property_ac);
1319     autocomplete_reset(auth_property_ac);
1320     autocomplete_reset(alias_ac);
1321     autocomplete_reset(aliases_ac);
1322     autocomplete_reset(join_property_ac);
1323     autocomplete_reset(room_ac);
1324     autocomplete_reset(rooms_all_ac);
1325     autocomplete_reset(rooms_list_ac);
1326     autocomplete_reset(rooms_cache_ac);
1327     autocomplete_reset(affiliation_ac);
1328     autocomplete_reset(role_ac);
1329     autocomplete_reset(affiliation_cmd_ac);
1330     autocomplete_reset(role_cmd_ac);
1331     autocomplete_reset(subject_ac);
1332     autocomplete_reset(form_ac);
1333     autocomplete_reset(form_field_multi_ac);
1334     autocomplete_reset(occupants_ac);
1335     autocomplete_reset(occupants_char_ac);
1336     autocomplete_reset(occupants_default_ac);
1337     autocomplete_reset(occupants_show_ac);
1338     autocomplete_reset(occupants_header_ac);
1339     autocomplete_reset(occupants_header_char_ac);
1340     autocomplete_reset(time_ac);
1341     autocomplete_reset(time_format_ac);
1342     autocomplete_reset(resource_ac);
1343     autocomplete_reset(inpblock_ac);
1344     autocomplete_reset(receipts_ac);
1345 #ifdef HAVE_LIBGPGME
1346     autocomplete_reset(pgp_ac);
1347     autocomplete_reset(pgp_log_ac);
1348     autocomplete_reset(pgp_sendfile_ac);
1349 #endif
1350     autocomplete_reset(tls_ac);
1351     autocomplete_reset(titlebar_ac);
1352     autocomplete_reset(titlebar_show_ac);
1353     autocomplete_reset(tls_certpath_ac);
1354     autocomplete_reset(console_ac);
1355     autocomplete_reset(console_msg_ac);
1356     autocomplete_reset(autoping_ac);
1357     autocomplete_reset(plugins_ac);
1358     autocomplete_reset(plugins_sourcepath_ac);
1359     autocomplete_reset(blocked_ac);
1360     autocomplete_reset(tray_ac);
1361     autocomplete_reset(presence_ac);
1362     autocomplete_reset(presence_setting_ac);
1363     autocomplete_reset(winpos_ac);
1364     autocomplete_reset(statusbar_ac);
1365     autocomplete_reset(statusbar_self_ac);
1366     autocomplete_reset(statusbar_chat_ac);
1367     autocomplete_reset(statusbar_room_ac);
1368     autocomplete_reset(statusbar_show_ac);
1369     autocomplete_reset(clear_ac);
1370     autocomplete_reset(invite_ac);
1371     autocomplete_reset(status_ac);
1372     autocomplete_reset(status_state_ac);
1373     autocomplete_reset(logging_ac);
1374     autocomplete_reset(logging_group_ac);
1375     autocomplete_reset(color_ac);
1376     autocomplete_reset(correction_ac);
1377     autocomplete_reset(avatar_ac);
1378     autocomplete_reset(url_ac);
1379     autocomplete_reset(executable_ac);
1380     autocomplete_reset(intype_ac);
1381 
1382     autocomplete_reset(script_ac);
1383     if (script_show_ac) {
1384         autocomplete_free(script_show_ac);
1385         script_show_ac = NULL;
1386     }
1387 
1388     if (window->type == WIN_MUC) {
1389         ProfMucWin* mucwin = (ProfMucWin*)window;
1390         assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
1391         muc_autocomplete_reset(mucwin->roomjid);
1392         muc_jid_autocomplete_reset(mucwin->roomjid);
1393     }
1394 
1395     if (window->type == WIN_CONFIG) {
1396         ProfConfWin* confwin = (ProfConfWin*)window;
1397         assert(confwin->memcheck == PROFCONFWIN_MEMCHECK);
1398         if (confwin->form) {
1399             form_reset_autocompleters(confwin->form);
1400         }
1401     }
1402 
1403     bookmark_autocomplete_reset();
1404     blocked_ac_reset();
1405     prefs_reset_room_trigger_ac();
1406     win_reset_search_attempts();
1407     win_close_reset_search_attempts();
1408     plugins_reset_autocomplete();
1409 }
1410 
1411 void
cmd_ac_uninit(void)1412 cmd_ac_uninit(void)
1413 {
1414     autocomplete_free(commands_ac);
1415     autocomplete_free(who_room_ac);
1416     autocomplete_free(who_roster_ac);
1417     autocomplete_free(help_ac);
1418     autocomplete_free(help_commands_ac);
1419     autocomplete_free(notify_ac);
1420     autocomplete_free(notify_chat_ac);
1421     autocomplete_free(notify_room_ac);
1422     autocomplete_free(notify_typing_ac);
1423     autocomplete_free(notify_mention_ac);
1424     autocomplete_free(notify_trigger_ac);
1425     autocomplete_free(sub_ac);
1426     autocomplete_free(wintitle_ac);
1427     autocomplete_free(log_ac);
1428     autocomplete_free(prefs_ac);
1429     autocomplete_free(autoaway_ac);
1430     autocomplete_free(autoaway_mode_ac);
1431     autocomplete_free(autoaway_presence_ac);
1432     autocomplete_free(autoconnect_ac);
1433     autocomplete_free(theme_ac);
1434     autocomplete_free(theme_load_ac);
1435     autocomplete_free(account_ac);
1436     autocomplete_free(account_set_ac);
1437     autocomplete_free(account_clear_ac);
1438     autocomplete_free(account_default_ac);
1439     autocomplete_free(account_status_ac);
1440     autocomplete_free(disco_ac);
1441     autocomplete_free(wins_ac);
1442     autocomplete_free(roster_ac);
1443     autocomplete_free(roster_header_ac);
1444     autocomplete_free(roster_contact_ac);
1445     autocomplete_free(roster_resource_ac);
1446     autocomplete_free(roster_presence_ac);
1447     autocomplete_free(roster_char_ac);
1448     autocomplete_free(roster_show_ac);
1449     autocomplete_free(roster_by_ac);
1450     autocomplete_free(roster_count_ac);
1451     autocomplete_free(roster_order_ac);
1452     autocomplete_free(roster_room_ac);
1453     autocomplete_free(roster_room_show_ac);
1454     autocomplete_free(roster_room_use_ac);
1455     autocomplete_free(roster_room_by_ac);
1456     autocomplete_free(roster_unread_ac);
1457     autocomplete_free(roster_room_position_ac);
1458     autocomplete_free(roster_room_order_ac);
1459     autocomplete_free(roster_remove_all_ac);
1460     autocomplete_free(roster_private_ac);
1461     autocomplete_free(group_ac);
1462     autocomplete_free(bookmark_ac);
1463     autocomplete_free(bookmark_property_ac);
1464     autocomplete_free(bookmark_ignore_ac);
1465 #ifdef HAVE_LIBOTR
1466     autocomplete_free(otr_ac);
1467     autocomplete_free(otr_log_ac);
1468     autocomplete_free(otr_policy_ac);
1469     autocomplete_free(otr_sendfile_ac);
1470 #endif
1471 #ifdef HAVE_OMEMO
1472     autocomplete_free(omemo_ac);
1473     autocomplete_free(omemo_log_ac);
1474     autocomplete_free(omemo_policy_ac);
1475     autocomplete_free(omemo_trustmode_ac);
1476 #endif
1477     autocomplete_free(connect_property_ac);
1478     autocomplete_free(tls_property_ac);
1479     autocomplete_free(auth_property_ac);
1480     autocomplete_free(alias_ac);
1481     autocomplete_free(aliases_ac);
1482     autocomplete_free(join_property_ac);
1483     autocomplete_free(room_ac);
1484     autocomplete_free(rooms_all_ac);
1485     autocomplete_free(rooms_list_ac);
1486     autocomplete_free(rooms_cache_ac);
1487     autocomplete_free(affiliation_ac);
1488     autocomplete_free(role_ac);
1489     autocomplete_free(affiliation_cmd_ac);
1490     autocomplete_free(role_cmd_ac);
1491     autocomplete_free(subject_ac);
1492     autocomplete_free(form_ac);
1493     autocomplete_free(form_field_multi_ac);
1494     autocomplete_free(occupants_ac);
1495     autocomplete_free(occupants_char_ac);
1496     autocomplete_free(occupants_default_ac);
1497     autocomplete_free(occupants_show_ac);
1498     autocomplete_free(occupants_header_ac);
1499     autocomplete_free(time_ac);
1500     autocomplete_free(time_format_ac);
1501     autocomplete_free(resource_ac);
1502     autocomplete_free(inpblock_ac);
1503     autocomplete_free(receipts_ac);
1504 #ifdef HAVE_LIBGPGME
1505     autocomplete_free(pgp_ac);
1506     autocomplete_free(pgp_log_ac);
1507     autocomplete_free(pgp_sendfile_ac);
1508 #endif
1509     autocomplete_free(tls_ac);
1510     autocomplete_free(titlebar_ac);
1511     autocomplete_free(titlebar_show_ac);
1512     autocomplete_free(tls_certpath_ac);
1513     autocomplete_free(script_ac);
1514     autocomplete_free(script_show_ac);
1515     autocomplete_free(console_ac);
1516     autocomplete_free(console_msg_ac);
1517     autocomplete_free(autoping_ac);
1518     autocomplete_free(plugins_ac);
1519     autocomplete_free(plugins_load_ac);
1520     autocomplete_free(plugins_unload_ac);
1521     autocomplete_free(plugins_reload_ac);
1522     autocomplete_free(filepath_ac);
1523     autocomplete_free(blocked_ac);
1524     autocomplete_free(tray_ac);
1525     autocomplete_free(presence_ac);
1526     autocomplete_free(presence_setting_ac);
1527     autocomplete_free(winpos_ac);
1528     autocomplete_free(statusbar_ac);
1529     autocomplete_free(statusbar_self_ac);
1530     autocomplete_free(statusbar_chat_ac);
1531     autocomplete_free(statusbar_room_ac);
1532     autocomplete_free(statusbar_show_ac);
1533     autocomplete_free(clear_ac);
1534     autocomplete_free(invite_ac);
1535     autocomplete_free(status_ac);
1536     autocomplete_free(status_state_ac);
1537     autocomplete_free(logging_ac);
1538     autocomplete_free(logging_group_ac);
1539     autocomplete_free(color_ac);
1540     autocomplete_free(correction_ac);
1541     autocomplete_free(avatar_ac);
1542     autocomplete_free(url_ac);
1543     autocomplete_free(executable_ac);
1544     autocomplete_free(intype_ac);
1545 }
1546 
1547 static void
_filepath_item_free(char ** ptr)1548 _filepath_item_free(char** ptr)
1549 {
1550     char* item = *ptr;
1551     free(item);
1552 }
1553 
1554 char*
cmd_ac_complete_filepath(const char * const input,char * const startstr,gboolean previous)1555 cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean previous)
1556 {
1557     unsigned int output_off = 0;
1558     char* tmp;
1559 
1560     // strip command
1561     char* inpcp = (char*)input + strlen(startstr);
1562     while (*inpcp == ' ') {
1563         inpcp++;
1564     }
1565 
1566     inpcp = strdup(inpcp);
1567 
1568     // strip quotes
1569     if (*inpcp == '"') {
1570         tmp = strchr(inpcp + 1, '"');
1571         if (tmp) {
1572             *tmp = '\0';
1573         }
1574         tmp = strdup(inpcp + 1);
1575         free(inpcp);
1576         inpcp = tmp;
1577     }
1578 
1579     // expand ~ to $HOME
1580     if (inpcp[0] == '~' && inpcp[1] == '/') {
1581         tmp = g_strdup_printf("%s/%sfoo", getenv("HOME"), inpcp + 2);
1582         if (!tmp) {
1583             free(inpcp);
1584             return NULL;
1585         }
1586         output_off = strlen(getenv("HOME")) + 1;
1587     } else {
1588         tmp = g_strdup_printf("%sfoo", inpcp);
1589         if (!tmp) {
1590             free(inpcp);
1591             return NULL;
1592         }
1593     }
1594     free(inpcp);
1595     inpcp = tmp;
1596 
1597     char* inpcp2 = strdup(inpcp);
1598     char* foofile = strdup(basename(inpcp2));
1599     char* directory = strdup(dirname(inpcp));
1600     free(inpcp);
1601     free(inpcp2);
1602 
1603     GArray* files = g_array_new(TRUE, FALSE, sizeof(char*));
1604     g_array_set_clear_func(files, (GDestroyNotify)_filepath_item_free);
1605 
1606     DIR* d = opendir(directory);
1607     if (d) {
1608         struct dirent* dir;
1609 
1610         while ((dir = readdir(d)) != NULL) {
1611             if (strcmp(dir->d_name, ".") == 0) {
1612                 continue;
1613             } else if (strcmp(dir->d_name, "..") == 0) {
1614                 continue;
1615             } else if (*(dir->d_name) == '.' && *foofile != '.') {
1616                 // only show hidden files on explicit request
1617                 continue;
1618             }
1619 
1620             char* acstring;
1621             if (output_off) {
1622                 tmp = g_strdup_printf("%s/%s", directory, dir->d_name);
1623                 if(!tmp) {
1624                     free(directory);
1625                     free(foofile);
1626                     return NULL;
1627                 }
1628                 acstring = g_strdup_printf("~/%s", tmp + output_off);
1629                 if (!acstring) {
1630                     free(directory);
1631                     free(foofile);
1632                     return NULL;
1633                 }
1634                 free(tmp);
1635             } else if (strcmp(directory, "/") == 0) {
1636                 acstring = g_strdup_printf("/%s", dir->d_name);
1637                 if (!acstring) {
1638                     free(directory);
1639                     free(foofile);
1640                     return NULL;
1641                 }
1642             } else {
1643                 acstring = g_strdup_printf("%s/%s", directory, dir->d_name);
1644                 if (!acstring) {
1645                     free(directory);
1646                     free(foofile);
1647                     return NULL;
1648                 }
1649             }
1650 
1651             char* acstring_cpy = strdup(acstring);
1652             g_array_append_val(files, acstring_cpy);
1653             free(acstring);
1654         }
1655         closedir(d);
1656     }
1657     free(directory);
1658     free(foofile);
1659 
1660     autocomplete_update(filepath_ac, (char**)files->data);
1661     g_array_free(files, TRUE);
1662 
1663     return autocomplete_param_with_ac(input, startstr, filepath_ac, TRUE, previous);
1664 }
1665 
1666 static char*
_cmd_ac_complete_params(ProfWin * window,const char * const input,gboolean previous)1667 _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previous)
1668 {
1669     char* result = NULL;
1670 
1671     jabber_conn_status_t conn_status = connection_get_status();
1672 
1673     // autocomplete boolean settings
1674     gchar* boolean_choices[] = { "/beep", "/states", "/outtype", "/flash", "/splash",
1675                                  "/history", "/vercheck", "/privileges", "/wrap",
1676                                  "/carbons", "/os", "/slashguard", "/mam", "/silence" };
1677 
1678     for (int i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
1679         result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice, previous, NULL);
1680         if (result) {
1681             return result;
1682         }
1683     }
1684 
1685     // autocomplete nickname in chat rooms
1686     if (window->type == WIN_MUC) {
1687         ProfMucWin* mucwin = (ProfMucWin*)window;
1688         assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
1689         Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
1690         if (nick_ac) {
1691             gchar* nick_choices[] = { "/msg", "/info", "/caps" };
1692 
1693             // Remove quote character before and after names when doing autocomplete
1694             char* unquoted = strip_arg_quotes(input);
1695             for (int i = 0; i < ARRAY_SIZE(nick_choices); i++) {
1696                 result = autocomplete_param_with_ac(unquoted, nick_choices[i], nick_ac, TRUE, previous);
1697                 if (result) {
1698                     free(unquoted);
1699                     return result;
1700                 }
1701             }
1702             free(unquoted);
1703         }
1704 
1705         // otherwise autocomplete using roster
1706     } else if (conn_status == JABBER_CONNECTED) {
1707         gchar* contact_choices[] = { "/msg", "/info" };
1708         // Remove quote character before and after names when doing autocomplete
1709         char* unquoted = strip_arg_quotes(input);
1710         for (int i = 0; i < ARRAY_SIZE(contact_choices); i++) {
1711             result = autocomplete_param_with_func(unquoted, contact_choices[i], roster_contact_autocomplete, previous, NULL);
1712             if (result) {
1713                 free(unquoted);
1714                 return result;
1715             }
1716         }
1717         free(unquoted);
1718 
1719         gchar* resource_choices[] = { "/caps", "/ping" };
1720         for (int i = 0; i < ARRAY_SIZE(resource_choices); i++) {
1721             result = autocomplete_param_with_func(input, resource_choices[i], roster_fulljid_autocomplete, previous, NULL);
1722             if (result) {
1723                 return result;
1724             }
1725         }
1726     }
1727 
1728     gchar* invite_choices[] = { "/join" };
1729     for (int i = 0; i < ARRAY_SIZE(invite_choices); i++) {
1730         result = autocomplete_param_with_func(input, invite_choices[i], muc_invites_find, previous, NULL);
1731         if (result) {
1732             return result;
1733         }
1734     }
1735 
1736     gchar* cmds[] = { "/prefs", "/disco", "/room", "/autoping", "/mainwin", "/inputwin" };
1737     Autocomplete completers[] = { prefs_ac, disco_ac, room_ac, autoping_ac, winpos_ac, winpos_ac };
1738 
1739     for (int i = 0; i < ARRAY_SIZE(cmds); i++) {
1740         result = autocomplete_param_with_ac(input, cmds[i], completers[i], TRUE, previous);
1741         if (result) {
1742             return result;
1743         }
1744     }
1745 
1746     GHashTable* ac_funcs = g_hash_table_new(g_str_hash, g_str_equal);
1747     g_hash_table_insert(ac_funcs, "/help", _help_autocomplete);
1748     g_hash_table_insert(ac_funcs, "/who", _who_autocomplete);
1749     g_hash_table_insert(ac_funcs, "/sub", _sub_autocomplete);
1750     g_hash_table_insert(ac_funcs, "/notify", _notify_autocomplete);
1751     g_hash_table_insert(ac_funcs, "/autoaway", _autoaway_autocomplete);
1752     g_hash_table_insert(ac_funcs, "/theme", _theme_autocomplete);
1753     g_hash_table_insert(ac_funcs, "/log", _log_autocomplete);
1754     g_hash_table_insert(ac_funcs, "/account", _account_autocomplete);
1755     g_hash_table_insert(ac_funcs, "/roster", _roster_autocomplete);
1756     g_hash_table_insert(ac_funcs, "/bookmark", _bookmark_autocomplete);
1757     g_hash_table_insert(ac_funcs, "/autoconnect", _autoconnect_autocomplete);
1758 #ifdef HAVE_LIBOTR
1759     g_hash_table_insert(ac_funcs, "/otr", _otr_autocomplete);
1760 #endif
1761 #ifdef HAVE_LIBGPGME
1762     g_hash_table_insert(ac_funcs, "/pgp", _pgp_autocomplete);
1763     g_hash_table_insert(ac_funcs, "/ox", _ox_autocomplete);
1764 #endif
1765 #ifdef HAVE_OMEMO
1766     g_hash_table_insert(ac_funcs, "/omemo", _omemo_autocomplete);
1767 #endif
1768     g_hash_table_insert(ac_funcs, "/connect", _connect_autocomplete);
1769     g_hash_table_insert(ac_funcs, "/alias", _alias_autocomplete);
1770     g_hash_table_insert(ac_funcs, "/join", _join_autocomplete);
1771     g_hash_table_insert(ac_funcs, "/form", _form_autocomplete);
1772     g_hash_table_insert(ac_funcs, "/occupants", _occupants_autocomplete);
1773     g_hash_table_insert(ac_funcs, "/kick", _kick_autocomplete);
1774     g_hash_table_insert(ac_funcs, "/ban", _ban_autocomplete);
1775     g_hash_table_insert(ac_funcs, "/affiliation", _affiliation_autocomplete);
1776     g_hash_table_insert(ac_funcs, "/role", _role_autocomplete);
1777     g_hash_table_insert(ac_funcs, "/resource", _resource_autocomplete);
1778     g_hash_table_insert(ac_funcs, "/wintitle", _wintitle_autocomplete);
1779     g_hash_table_insert(ac_funcs, "/inpblock", _inpblock_autocomplete);
1780     g_hash_table_insert(ac_funcs, "/time", _time_autocomplete);
1781     g_hash_table_insert(ac_funcs, "/receipts", _receipts_autocomplete);
1782     g_hash_table_insert(ac_funcs, "/wins", _wins_autocomplete);
1783     g_hash_table_insert(ac_funcs, "/tls", _tls_autocomplete);
1784     g_hash_table_insert(ac_funcs, "/titlebar", _titlebar_autocomplete);
1785     g_hash_table_insert(ac_funcs, "/script", _script_autocomplete);
1786     g_hash_table_insert(ac_funcs, "/subject", _subject_autocomplete);
1787     g_hash_table_insert(ac_funcs, "/console", _console_autocomplete);
1788     g_hash_table_insert(ac_funcs, "/win", _win_autocomplete);
1789     g_hash_table_insert(ac_funcs, "/close", _close_autocomplete);
1790     g_hash_table_insert(ac_funcs, "/plugins", _plugins_autocomplete);
1791     g_hash_table_insert(ac_funcs, "/sendfile", _sendfile_autocomplete);
1792     g_hash_table_insert(ac_funcs, "/blocked", _blocked_autocomplete);
1793     g_hash_table_insert(ac_funcs, "/tray", _tray_autocomplete);
1794     g_hash_table_insert(ac_funcs, "/presence", _presence_autocomplete);
1795     g_hash_table_insert(ac_funcs, "/rooms", _rooms_autocomplete);
1796     g_hash_table_insert(ac_funcs, "/statusbar", _statusbar_autocomplete);
1797     g_hash_table_insert(ac_funcs, "/clear", _clear_autocomplete);
1798     g_hash_table_insert(ac_funcs, "/invite", _invite_autocomplete);
1799     g_hash_table_insert(ac_funcs, "/status", _status_autocomplete);
1800     g_hash_table_insert(ac_funcs, "/logging", _logging_autocomplete);
1801     g_hash_table_insert(ac_funcs, "/color", _color_autocomplete);
1802     g_hash_table_insert(ac_funcs, "/avatar", _avatar_autocomplete);
1803     g_hash_table_insert(ac_funcs, "/correction", _correction_autocomplete);
1804     g_hash_table_insert(ac_funcs, "/correct", _correct_autocomplete);
1805     g_hash_table_insert(ac_funcs, "/software", _software_autocomplete);
1806     g_hash_table_insert(ac_funcs, "/url", _url_autocomplete);
1807     g_hash_table_insert(ac_funcs, "/executable", _executable_autocomplete);
1808     g_hash_table_insert(ac_funcs, "/lastactivity", _lastactivity_autocomplete);
1809     g_hash_table_insert(ac_funcs, "/intype", _intype_autocomplete);
1810 
1811     int len = strlen(input);
1812     char parsed[len + 1];
1813     int i = 0;
1814     while (i < len) {
1815         if (input[i] == ' ') {
1816             break;
1817         } else {
1818             parsed[i] = input[i];
1819         }
1820         i++;
1821     }
1822     parsed[i] = '\0';
1823 
1824     char* (*ac_func)(ProfWin*, const char* const, gboolean) = g_hash_table_lookup(ac_funcs, parsed);
1825     if (ac_func) {
1826         result = ac_func(window, input, previous);
1827         if (result) {
1828             g_hash_table_destroy(ac_funcs);
1829             return result;
1830         }
1831     }
1832     g_hash_table_destroy(ac_funcs);
1833 
1834     result = plugins_autocomplete(input, previous);
1835     if (result) {
1836         return result;
1837     }
1838 
1839     if (g_str_has_prefix(input, "/field")) {
1840         result = _form_field_autocomplete(window, input, previous);
1841         if (result) {
1842             return result;
1843         }
1844     }
1845 
1846     return NULL;
1847 }
1848 
1849 static char*
_sub_autocomplete(ProfWin * window,const char * const input,gboolean previous)1850 _sub_autocomplete(ProfWin* window, const char* const input, gboolean previous)
1851 {
1852     char* result = NULL;
1853     result = autocomplete_param_with_func(input, "/sub allow", presence_sub_request_find, previous, NULL);
1854     if (result) {
1855         return result;
1856     }
1857     result = autocomplete_param_with_func(input, "/sub deny", presence_sub_request_find, previous, NULL);
1858     if (result) {
1859         return result;
1860     }
1861     result = autocomplete_param_with_ac(input, "/sub", sub_ac, TRUE, previous);
1862     return result;
1863 }
1864 
1865 static char*
_tray_autocomplete(ProfWin * window,const char * const input,gboolean previous)1866 _tray_autocomplete(ProfWin* window, const char* const input, gboolean previous)
1867 {
1868     char* result = NULL;
1869     result = autocomplete_param_with_func(input, "/tray read", prefs_autocomplete_boolean_choice, previous, NULL);
1870     if (result) {
1871         return result;
1872     }
1873 
1874     result = autocomplete_param_with_ac(input, "/tray", tray_ac, FALSE, previous);
1875     return result;
1876 }
1877 
1878 static char*
_who_autocomplete(ProfWin * window,const char * const input,gboolean previous)1879 _who_autocomplete(ProfWin* window, const char* const input, gboolean previous)
1880 {
1881     char* result = NULL;
1882 
1883     if (window->type == WIN_MUC) {
1884         result = autocomplete_param_with_ac(input, "/who", who_room_ac, TRUE, previous);
1885         if (result) {
1886             return result;
1887         }
1888     } else {
1889         jabber_conn_status_t conn_status = connection_get_status();
1890         if (conn_status == JABBER_CONNECTED) {
1891             gchar* group_commands[] = { "/who any", "/who online", "/who offline",
1892                                         "/who chat", "/who away", "/who xa", "/who dnd", "/who available",
1893                                         "/who unavailable" };
1894 
1895             for (int i = 0; i < ARRAY_SIZE(group_commands); i++) {
1896                 result = autocomplete_param_with_func(input, group_commands[i], roster_group_autocomplete, previous, NULL);
1897                 if (result) {
1898                     return result;
1899                 }
1900             }
1901         }
1902 
1903         result = autocomplete_param_with_ac(input, "/who", who_roster_ac, TRUE, previous);
1904     }
1905 
1906     return result;
1907 }
1908 
1909 static char*
_roster_autocomplete(ProfWin * window,const char * const input,gboolean previous)1910 _roster_autocomplete(ProfWin* window, const char* const input, gboolean previous)
1911 {
1912     char* result = NULL;
1913     result = autocomplete_param_with_ac(input, "/roster room private char", roster_char_ac, TRUE, previous);
1914     if (result) {
1915         return result;
1916     }
1917     result = autocomplete_param_with_ac(input, "/roster room private", roster_header_ac, TRUE, previous);
1918     if (result) {
1919         return result;
1920     }
1921     result = autocomplete_param_with_ac(input, "/roster header char", roster_char_ac, TRUE, previous);
1922     if (result) {
1923         return result;
1924     }
1925     result = autocomplete_param_with_ac(input, "/roster contact char", roster_char_ac, TRUE, previous);
1926     if (result) {
1927         return result;
1928     }
1929     result = autocomplete_param_with_ac(input, "/roster room char", roster_char_ac, TRUE, previous);
1930     if (result) {
1931         return result;
1932     }
1933     result = autocomplete_param_with_ac(input, "/roster private char", roster_char_ac, TRUE, previous);
1934     if (result) {
1935         return result;
1936     }
1937     result = autocomplete_param_with_ac(input, "/roster resource char", roster_char_ac, TRUE, previous);
1938     if (result) {
1939         return result;
1940     }
1941     result = autocomplete_param_with_func(input, "/roster resource join", prefs_autocomplete_boolean_choice, previous, NULL);
1942     if (result) {
1943         return result;
1944     }
1945     result = autocomplete_param_with_ac(input, "/roster room position", roster_room_position_ac, TRUE, previous);
1946     if (result) {
1947         return result;
1948     }
1949     result = autocomplete_param_with_ac(input, "/roster room by", roster_room_by_ac, TRUE, previous);
1950     if (result) {
1951         return result;
1952     }
1953     result = autocomplete_param_with_ac(input, "/roster room order", roster_room_order_ac, TRUE, previous);
1954     if (result) {
1955         return result;
1956     }
1957     result = autocomplete_param_with_ac(input, "/roster room unread", roster_unread_ac, TRUE, previous);
1958     if (result) {
1959         return result;
1960     }
1961     result = autocomplete_param_with_ac(input, "/roster room show", roster_room_show_ac, TRUE, previous);
1962     if (result) {
1963         return result;
1964     }
1965     result = autocomplete_param_with_ac(input, "/roster room hide", roster_room_show_ac, TRUE, previous);
1966     if (result) {
1967         return result;
1968     }
1969     result = autocomplete_param_with_ac(input, "/roster room use", roster_room_use_ac, TRUE, previous);
1970     if (result) {
1971         return result;
1972     }
1973     result = autocomplete_param_with_func(input, "/roster count zero", prefs_autocomplete_boolean_choice, previous, NULL);
1974     if (result) {
1975         return result;
1976     }
1977     result = autocomplete_param_with_func(input, "/roster color", prefs_autocomplete_boolean_choice, previous, NULL);
1978     if (result) {
1979         return result;
1980     }
1981 
1982     jabber_conn_status_t conn_status = connection_get_status();
1983     if (conn_status == JABBER_CONNECTED) {
1984         result = autocomplete_param_with_func(input, "/roster nick", roster_barejid_autocomplete, previous, NULL);
1985         if (result) {
1986             return result;
1987         }
1988         result = autocomplete_param_with_func(input, "/roster clearnick", roster_barejid_autocomplete, previous, NULL);
1989         if (result) {
1990             return result;
1991         }
1992         result = autocomplete_param_with_func(input, "/roster remove", roster_barejid_autocomplete, previous, NULL);
1993         if (result) {
1994             return result;
1995         }
1996 
1997         result = autocomplete_param_with_func(input, "/roster group show", roster_group_autocomplete, previous, NULL);
1998         if (result) {
1999             return result;
2000         }
2001         result = autocomplete_param_no_with_func(input, "/roster group add", 5, roster_contact_autocomplete, previous, NULL);
2002         if (result) {
2003             return result;
2004         }
2005         result = autocomplete_param_no_with_func(input, "/roster group remove", 5, roster_contact_autocomplete, previous, NULL);
2006         if (result) {
2007             return result;
2008         }
2009         result = autocomplete_param_with_func(input, "/roster group add", roster_group_autocomplete, previous, NULL);
2010         if (result) {
2011             return result;
2012         }
2013         result = autocomplete_param_with_func(input, "/roster group remove", roster_group_autocomplete, previous, NULL);
2014         if (result) {
2015             return result;
2016         }
2017     }
2018 
2019     result = autocomplete_param_with_ac(input, "/roster remove_all", roster_remove_all_ac, TRUE, previous);
2020     if (result) {
2021         return result;
2022     }
2023     result = autocomplete_param_with_ac(input, "/roster show", roster_show_ac, TRUE, previous);
2024     if (result) {
2025         return result;
2026     }
2027     result = autocomplete_param_with_ac(input, "/roster hide", roster_show_ac, TRUE, previous);
2028     if (result) {
2029         return result;
2030     }
2031     result = autocomplete_param_with_ac(input, "/roster by", roster_by_ac, TRUE, previous);
2032     if (result) {
2033         return result;
2034     }
2035     result = autocomplete_param_with_ac(input, "/roster count", roster_count_ac, TRUE, previous);
2036     if (result) {
2037         return result;
2038     }
2039     result = autocomplete_param_with_ac(input, "/roster order", roster_order_ac, TRUE, previous);
2040     if (result) {
2041         return result;
2042     }
2043     result = autocomplete_param_with_ac(input, "/roster unread", roster_unread_ac, TRUE, previous);
2044     if (result) {
2045         return result;
2046     }
2047     result = autocomplete_param_with_ac(input, "/roster room", roster_room_ac, TRUE, previous);
2048     if (result) {
2049         return result;
2050     }
2051     result = autocomplete_param_with_func(input, "/roster wrap", prefs_autocomplete_boolean_choice, previous, NULL);
2052     if (result) {
2053         return result;
2054     }
2055     result = autocomplete_param_with_ac(input, "/roster header", roster_header_ac, TRUE, previous);
2056     if (result) {
2057         return result;
2058     }
2059     result = autocomplete_param_with_ac(input, "/roster contact", roster_contact_ac, TRUE, previous);
2060     if (result) {
2061         return result;
2062     }
2063     result = autocomplete_param_with_ac(input, "/roster resource", roster_resource_ac, TRUE, previous);
2064     if (result) {
2065         return result;
2066     }
2067     result = autocomplete_param_with_ac(input, "/roster presence", roster_presence_ac, TRUE, previous);
2068     if (result) {
2069         return result;
2070     }
2071     result = autocomplete_param_with_ac(input, "/roster private", roster_private_ac, TRUE, previous);
2072     if (result) {
2073         return result;
2074     }
2075     result = autocomplete_param_with_ac(input, "/roster group", group_ac, TRUE, previous);
2076     if (result) {
2077         return result;
2078     }
2079     result = autocomplete_param_with_ac(input, "/roster", roster_ac, TRUE, previous);
2080     if (result) {
2081         return result;
2082     }
2083 
2084     return NULL;
2085 }
2086 
2087 static char*
_blocked_autocomplete(ProfWin * window,const char * const input,gboolean previous)2088 _blocked_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2089 {
2090     char* result = NULL;
2091 
2092     result = autocomplete_param_with_func(input, "/blocked remove", blocked_ac_find, previous, NULL);
2093     if (result) {
2094         return result;
2095     }
2096 
2097     result = autocomplete_param_with_ac(input, "/blocked", blocked_ac, FALSE, previous);
2098     if (result) {
2099         return result;
2100     }
2101 
2102     return NULL;
2103 }
2104 
2105 static char*
_bookmark_autocomplete(ProfWin * window,const char * const input,gboolean previous)2106 _bookmark_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2107 {
2108     char* found = NULL;
2109 
2110     gboolean result;
2111     gchar** args = parse_args(input, 2, 8, &result);
2112 
2113     if (result && ((strcmp(args[0], "add") == 0) || (strcmp(args[0], "update") == 0))) {
2114         gboolean space_at_end = g_str_has_suffix(input, " ");
2115         int num_args = g_strv_length(args);
2116         if ((num_args == 2 && space_at_end) || (num_args == 3 && !space_at_end)) {
2117             GString* beginning = g_string_new("/bookmark");
2118             g_string_append_printf(beginning, " %s %s", args[0], args[1]);
2119             found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE, previous);
2120             g_string_free(beginning, TRUE);
2121             if (found) {
2122                 g_strfreev(args);
2123                 return found;
2124             }
2125         }
2126         if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "autojoin") == 0))
2127             || (num_args == 4 && (g_strcmp0(args[2], "autojoin") == 0) && !space_at_end)) {
2128             GString* beginning = g_string_new("/bookmark");
2129             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
2130             found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
2131             g_string_free(beginning, TRUE);
2132             if (found) {
2133                 g_strfreev(args);
2134                 return found;
2135             }
2136         }
2137         if ((num_args == 4 && space_at_end) || (num_args == 5 && !space_at_end)) {
2138             GString* beginning = g_string_new("/bookmark");
2139             g_string_append_printf(beginning, " %s %s %s %s", args[0], args[1], args[2], args[3]);
2140             found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE, previous);
2141             g_string_free(beginning, TRUE);
2142             if (found) {
2143                 g_strfreev(args);
2144                 return found;
2145             }
2146         }
2147         if ((num_args == 5 && space_at_end && (g_strcmp0(args[4], "autojoin") == 0))
2148             || (num_args == 6 && (g_strcmp0(args[4], "autojoin") == 0) && !space_at_end)) {
2149             GString* beginning = g_string_new("/bookmark");
2150             g_string_append_printf(beginning, " %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4]);
2151             found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
2152             g_string_free(beginning, TRUE);
2153             if (found) {
2154                 g_strfreev(args);
2155                 return found;
2156             }
2157         }
2158         if ((num_args == 6 && space_at_end) || (num_args == 7 && !space_at_end)) {
2159             GString* beginning = g_string_new("/bookmark");
2160             g_string_append_printf(beginning, " %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5]);
2161             found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE, previous);
2162             g_string_free(beginning, TRUE);
2163             if (found) {
2164                 g_strfreev(args);
2165                 return found;
2166             }
2167         }
2168         if ((num_args == 7 && space_at_end && (g_strcmp0(args[6], "autojoin") == 0))
2169             || (num_args == 8 && (g_strcmp0(args[6], "autojoin") == 0) && !space_at_end)) {
2170             GString* beginning = g_string_new("/bookmark");
2171             g_string_append_printf(beginning, " %s %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
2172             found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
2173             g_string_free(beginning, TRUE);
2174             if (found) {
2175                 g_strfreev(args);
2176                 return found;
2177             }
2178         }
2179     }
2180 
2181     g_strfreev(args);
2182 
2183     found = autocomplete_param_with_func(input, "/bookmark remove", bookmark_find, previous, NULL);
2184     if (found) {
2185         return found;
2186     }
2187     found = autocomplete_param_with_func(input, "/bookmark join", bookmark_find, previous, NULL);
2188     if (found) {
2189         return found;
2190     }
2191     found = autocomplete_param_with_func(input, "/bookmark update", bookmark_find, previous, NULL);
2192     if (found) {
2193         return found;
2194     }
2195     found = autocomplete_param_with_func(input, "/bookmark invites", prefs_autocomplete_boolean_choice, previous, NULL);
2196     if (found) {
2197         return found;
2198     }
2199 
2200     found = autocomplete_param_with_ac(input, "/bookmark ignore", bookmark_ignore_ac, TRUE, previous);
2201     if (found) {
2202         return found;
2203     }
2204     found = autocomplete_param_with_func(input, "/bookmark ignore add", bookmark_find, previous, NULL);
2205     if (found) {
2206         return found;
2207     }
2208     found = autocomplete_param_with_func(input, "/bookmark ignore remove", bookmark_find, previous, NULL);
2209     if (found) {
2210         return found;
2211     }
2212     found = autocomplete_param_with_func(input, "/bookmark list", bookmark_find, previous, NULL);
2213     if (found) {
2214         return found;
2215     }
2216 
2217     found = autocomplete_param_with_ac(input, "/bookmark", bookmark_ac, TRUE, previous);
2218     return found;
2219 }
2220 
2221 static char*
_notify_autocomplete(ProfWin * window,const char * const input,gboolean previous)2222 _notify_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2223 {
2224     char* result = NULL;
2225 
2226     result = autocomplete_param_with_func(input, "/notify room trigger remove", prefs_autocomplete_room_trigger, previous, NULL);
2227     if (result) {
2228         return result;
2229     }
2230 
2231     gchar* boolean_choices1[] = { "/notify room current", "/notify chat current", "/notify typing current",
2232                                   "/notify room text", "/notify chat text" };
2233     for (int i = 0; i < ARRAY_SIZE(boolean_choices1); i++) {
2234         result = autocomplete_param_with_func(input, boolean_choices1[i], prefs_autocomplete_boolean_choice, previous, NULL);
2235         if (result) {
2236             return result;
2237         }
2238     }
2239 
2240     result = autocomplete_param_with_ac(input, "/notify room mention", notify_mention_ac, TRUE, previous);
2241     if (result) {
2242         return result;
2243     }
2244 
2245     result = autocomplete_param_with_ac(input, "/notify room trigger", notify_trigger_ac, TRUE, previous);
2246     if (result) {
2247         return result;
2248     }
2249 
2250     result = autocomplete_param_with_ac(input, "/notify room", notify_room_ac, TRUE, previous);
2251     if (result) {
2252         return result;
2253     }
2254 
2255     result = autocomplete_param_with_ac(input, "/notify chat", notify_chat_ac, TRUE, previous);
2256     if (result) {
2257         return result;
2258     }
2259 
2260     result = autocomplete_param_with_ac(input, "/notify typing", notify_typing_ac, TRUE, previous);
2261     if (result) {
2262         return result;
2263     }
2264 
2265     gchar* boolean_choices2[] = { "/notify invite", "/notify sub", "/notify mention", "/notify trigger" };
2266     for (int i = 0; i < ARRAY_SIZE(boolean_choices2); i++) {
2267         result = autocomplete_param_with_func(input, boolean_choices2[i], prefs_autocomplete_boolean_choice, previous, NULL);
2268         if (result) {
2269             return result;
2270         }
2271     }
2272 
2273     result = autocomplete_param_with_ac(input, "/notify", notify_ac, TRUE, previous);
2274     if (result) {
2275         return result;
2276     }
2277 
2278     return NULL;
2279 }
2280 
2281 static char*
_autoaway_autocomplete(ProfWin * window,const char * const input,gboolean previous)2282 _autoaway_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2283 {
2284     char* result = NULL;
2285 
2286     result = autocomplete_param_with_ac(input, "/autoaway mode", autoaway_mode_ac, TRUE, previous);
2287     if (result) {
2288         return result;
2289     }
2290 
2291     result = autocomplete_param_with_ac(input, "/autoaway time", autoaway_presence_ac, TRUE, previous);
2292     if (result) {
2293         return result;
2294     }
2295 
2296     result = autocomplete_param_with_ac(input, "/autoaway message", autoaway_presence_ac, TRUE, previous);
2297     if (result) {
2298         return result;
2299     }
2300 
2301     result = autocomplete_param_with_func(input, "/autoaway check", prefs_autocomplete_boolean_choice, previous, NULL);
2302     if (result) {
2303         return result;
2304     }
2305     result = autocomplete_param_with_ac(input, "/autoaway", autoaway_ac, TRUE, previous);
2306     if (result) {
2307         return result;
2308     }
2309 
2310     return NULL;
2311 }
2312 
2313 static char*
_log_autocomplete(ProfWin * window,const char * const input,gboolean previous)2314 _log_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2315 {
2316     char* result = NULL;
2317 
2318     result = autocomplete_param_with_func(input, "/log rotate", prefs_autocomplete_boolean_choice, previous, NULL);
2319     if (result) {
2320         return result;
2321     }
2322     result = autocomplete_param_with_func(input, "/log shared", prefs_autocomplete_boolean_choice, previous, NULL);
2323     if (result) {
2324         return result;
2325     }
2326     result = autocomplete_param_with_ac(input, "/log", log_ac, TRUE, previous);
2327     if (result) {
2328         return result;
2329     }
2330 
2331     return NULL;
2332 }
2333 
2334 static char*
_autoconnect_autocomplete(ProfWin * window,const char * const input,gboolean previous)2335 _autoconnect_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2336 {
2337     char* result = NULL;
2338 
2339     result = autocomplete_param_with_func(input, "/autoconnect set", accounts_find_enabled, previous, NULL);
2340     if (result) {
2341         return result;
2342     }
2343 
2344     result = autocomplete_param_with_ac(input, "/autoconnect", autoconnect_ac, TRUE, previous);
2345     if (result) {
2346         return result;
2347     }
2348 
2349     return NULL;
2350 }
2351 
2352 #ifdef HAVE_LIBOTR
2353 static char*
_otr_autocomplete(ProfWin * window,const char * const input,gboolean previous)2354 _otr_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2355 {
2356     char* found = NULL;
2357 
2358     jabber_conn_status_t conn_status = connection_get_status();
2359 
2360     if (conn_status == JABBER_CONNECTED) {
2361         found = autocomplete_param_with_func(input, "/otr start", roster_contact_autocomplete, previous, NULL);
2362         if (found) {
2363             return found;
2364         }
2365     }
2366 
2367     found = autocomplete_param_with_ac(input, "/otr log", otr_log_ac, TRUE, previous);
2368     if (found) {
2369         return found;
2370     }
2371 
2372     // /otr policy always user@server.com
2373     if (conn_status == JABBER_CONNECTED) {
2374         gboolean result;
2375         gchar** args = parse_args(input, 2, 3, &result);
2376         if (result && (strcmp(args[0], "policy") == 0)) {
2377             GString* beginning = g_string_new("/otr ");
2378             g_string_append(beginning, args[0]);
2379             g_string_append(beginning, " ");
2380             if (args[1]) {
2381                 g_string_append(beginning, args[1]);
2382             }
2383 
2384             found = autocomplete_param_with_func(input, beginning->str, roster_contact_autocomplete, previous, NULL);
2385             g_string_free(beginning, TRUE);
2386             if (found) {
2387                 g_strfreev(args);
2388                 return found;
2389             }
2390         }
2391         g_strfreev(args);
2392     }
2393 
2394     found = autocomplete_param_with_ac(input, "/otr policy", otr_policy_ac, TRUE, previous);
2395     if (found) {
2396         return found;
2397     }
2398 
2399     found = autocomplete_param_with_ac(input, "/otr sendfile", otr_sendfile_ac, TRUE, previous);
2400     if (found) {
2401         return found;
2402     }
2403 
2404     found = autocomplete_param_with_ac(input, "/otr", otr_ac, TRUE, previous);
2405     if (found) {
2406         return found;
2407     }
2408 
2409     return NULL;
2410 }
2411 #endif
2412 
2413 #ifdef HAVE_LIBGPGME
2414 static char*
_pgp_autocomplete(ProfWin * window,const char * const input,gboolean previous)2415 _pgp_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2416 {
2417     char* found = NULL;
2418 
2419     jabber_conn_status_t conn_status = connection_get_status();
2420 
2421     if (conn_status == JABBER_CONNECTED) {
2422         found = autocomplete_param_with_func(input, "/pgp start", roster_contact_autocomplete, previous, NULL);
2423         if (found) {
2424             return found;
2425         }
2426     }
2427 
2428     found = autocomplete_param_with_ac(input, "/pgp log", pgp_log_ac, TRUE, previous);
2429     if (found) {
2430         return found;
2431     }
2432 
2433     found = autocomplete_param_with_ac(input, "/pgp sendfile", pgp_sendfile_ac, TRUE, previous);
2434     if (found) {
2435         return found;
2436     }
2437 
2438     gboolean result;
2439     gchar** args = parse_args(input, 2, 3, &result);
2440     if ((strncmp(input, "/pgp", 4) == 0) && (result == TRUE)) {
2441         GString* beginning = g_string_new("/pgp ");
2442         g_string_append(beginning, args[0]);
2443         if (args[1]) {
2444             g_string_append(beginning, " ");
2445             g_string_append(beginning, args[1]);
2446         }
2447         found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous, NULL);
2448         g_string_free(beginning, TRUE);
2449         if (found) {
2450             g_strfreev(args);
2451             return found;
2452         }
2453     }
2454     g_strfreev(args);
2455 
2456     if (conn_status == JABBER_CONNECTED) {
2457         found = autocomplete_param_with_func(input, "/pgp setkey", roster_barejid_autocomplete, previous, NULL);
2458         if (found) {
2459             return found;
2460         }
2461     }
2462 
2463     found = autocomplete_param_with_ac(input, "/pgp", pgp_ac, TRUE, previous);
2464     if (found) {
2465         return found;
2466     }
2467 
2468     return NULL;
2469 }
2470 
2471 /*!
2472  * \brief Auto completion for XEP-0373: OpenPGP for XMPP command.
2473  *
2474  *
2475  */
2476 static char*
_ox_autocomplete(ProfWin * window,const char * const input,gboolean previous)2477 _ox_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2478 {
2479     char* found = NULL;
2480 
2481     jabber_conn_status_t conn_status = connection_get_status();
2482 
2483     if (conn_status == JABBER_CONNECTED) {
2484         found = autocomplete_param_with_func(input, "/ox start", roster_contact_autocomplete, previous, NULL);
2485         if (found) {
2486             return found;
2487         }
2488     }
2489 
2490     if (conn_status == JABBER_CONNECTED) {
2491         found = autocomplete_param_with_func(input, "/ox discover", roster_contact_autocomplete, previous, NULL);
2492          if (found) {
2493              return found;
2494         }
2495     }
2496 
2497     found = autocomplete_param_with_ac(input, "/ox log", ox_log_ac, TRUE, previous);
2498     if (found) {
2499         return found;
2500     }
2501 
2502     found = autocomplete_param_with_ac(input, "/ox sendfile", ox_sendfile_ac, TRUE, previous);
2503     if (found) {
2504         return found;
2505     }
2506 
2507     gboolean result;
2508     gchar** args = parse_args(input, 2, 3, &result);
2509     if ((strncmp(input, "/ox", 4) == 0) && (result == TRUE)) {
2510         GString* beginning = g_string_new("/ox ");
2511         g_string_append(beginning, args[0]);
2512         if (args[1]) {
2513             g_string_append(beginning, " ");
2514             g_string_append(beginning, args[1]);
2515         }
2516         found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous, NULL);
2517         g_string_free(beginning, TRUE);
2518         if (found) {
2519             g_strfreev(args);
2520             return found;
2521         }
2522     }
2523     g_strfreev(args);
2524 
2525     if (conn_status == JABBER_CONNECTED) {
2526         found = autocomplete_param_with_func(input, "/ox setkey", roster_barejid_autocomplete, previous, NULL);
2527         if (found) {
2528             return found;
2529         }
2530     }
2531 
2532     found = autocomplete_param_with_ac(input, "/ox", ox_ac, TRUE, previous);
2533 
2534     return found;
2535 }
2536 #endif
2537 
2538 #ifdef HAVE_OMEMO
2539 static char*
_omemo_autocomplete(ProfWin * window,const char * const input,gboolean previous)2540 _omemo_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2541 {
2542     char* found = NULL;
2543 
2544     found = autocomplete_param_with_ac(input, "/omemo log", omemo_log_ac, TRUE, previous);
2545     if (found) {
2546         return found;
2547     }
2548 
2549     found = autocomplete_param_with_ac(input, "/omemo policy", omemo_policy_ac, TRUE, previous);
2550     if (found) {
2551         return found;
2552     }
2553 
2554     found = autocomplete_param_with_ac(input, "/omemo trustmode", omemo_trustmode_ac, TRUE, previous);
2555     if (found) {
2556         return found;
2557     }
2558 
2559     jabber_conn_status_t conn_status = connection_get_status();
2560 
2561     if (conn_status == JABBER_CONNECTED) {
2562         found = autocomplete_param_with_func(input, "/omemo start", roster_contact_autocomplete, previous, NULL);
2563         if (found) {
2564             return found;
2565         }
2566 
2567         found = autocomplete_param_with_func(input, "/omemo fingerprint", roster_contact_autocomplete, previous, NULL);
2568         if (found) {
2569             return found;
2570         }
2571 
2572         if (window->type == WIN_CHAT) {
2573             ProfChatWin* chatwin = (ProfChatWin*)window;
2574             assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
2575             found = autocomplete_param_with_func(input, "/omemo trust", omemo_fingerprint_autocomplete, previous, chatwin->barejid);
2576             if (found) {
2577                 return found;
2578             }
2579         } else {
2580             found = autocomplete_param_with_func(input, "/omemo trust", roster_contact_autocomplete, previous, NULL);
2581             if (found) {
2582                 return found;
2583             }
2584 
2585             int num_tokens = count_tokens(input);
2586             if (num_tokens == 4) {
2587                 gboolean result;
2588                 gchar** args = parse_args(input, 2, 3, &result);
2589                 if (result) {
2590                     gchar* jid = g_strdup(args[1]);
2591                     found = autocomplete_param_no_with_func(input, "/omemo trust", 4, omemo_fingerprint_autocomplete, previous, jid);
2592                     if (found) {
2593                         return found;
2594                     }
2595                 }
2596             }
2597         }
2598 
2599         if (window->type == WIN_CHAT) {
2600             ProfChatWin* chatwin = (ProfChatWin*)window;
2601             assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
2602             found = autocomplete_param_with_func(input, "/omemo untrust", omemo_fingerprint_autocomplete, previous, chatwin->barejid);
2603             if (found) {
2604                 return found;
2605             }
2606         } else {
2607             found = autocomplete_param_with_func(input, "/omemo untrust", roster_contact_autocomplete, previous, NULL);
2608             if (found) {
2609                 return found;
2610             }
2611 
2612             int num_tokens = count_tokens(input);
2613             if (num_tokens == 4) {
2614                 gboolean result;
2615                 gchar** args = parse_args(input, 2, 3, &result);
2616                 if (result) {
2617                     gchar* jid = g_strdup(args[1]);
2618                     found = autocomplete_param_no_with_func(input, "/omemo untrust", 4, omemo_fingerprint_autocomplete, previous, jid);
2619                     if (found) {
2620                         return found;
2621                     }
2622                 }
2623             }
2624         }
2625     }
2626 
2627     found = autocomplete_param_with_ac(input, "/omemo", omemo_ac, TRUE, previous);
2628     if (found) {
2629         return found;
2630     }
2631 
2632     return NULL;
2633 }
2634 #endif
2635 
2636 static char*
_plugins_autocomplete(ProfWin * window,const char * const input,gboolean previous)2637 _plugins_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2638 {
2639     char* result = NULL;
2640 
2641     if (strncmp(input, "/plugins sourcepath set ", 24) == 0) {
2642         return cmd_ac_complete_filepath(input, "/plugins sourcepath set", previous);
2643     }
2644 
2645     if (strncmp(input, "/plugins install ", 17) == 0) {
2646         return cmd_ac_complete_filepath(input, "/plugins install", previous);
2647     }
2648 
2649     if (strncmp(input, "/plugins sourcepath ", 20) == 0) {
2650         result = autocomplete_param_with_ac(input, "/plugins sourcepath", plugins_sourcepath_ac, TRUE, previous);
2651         if (result) {
2652             return result;
2653         }
2654     }
2655 
2656     if (strncmp(input, "/plugins load ", 14) == 0) {
2657         if (plugins_load_ac == NULL) {
2658             plugins_load_ac = autocomplete_new();
2659             GSList* plugins = plugins_unloaded_list();
2660             GSList* curr = plugins;
2661             while (curr) {
2662                 autocomplete_add(plugins_load_ac, curr->data);
2663                 curr = g_slist_next(curr);
2664             }
2665             g_slist_free_full(plugins, g_free);
2666         }
2667         result = autocomplete_param_with_ac(input, "/plugins load", plugins_load_ac, TRUE, previous);
2668         if (result) {
2669             return result;
2670         }
2671     }
2672 
2673     if (strncmp(input, "/plugins reload ", 16) == 0) {
2674         if (plugins_reload_ac == NULL) {
2675             plugins_reload_ac = autocomplete_new();
2676             GList* plugins = plugins_loaded_list();
2677             GList* curr = plugins;
2678             while (curr) {
2679                 autocomplete_add(plugins_reload_ac, curr->data);
2680                 curr = g_list_next(curr);
2681             }
2682             g_list_free(plugins);
2683         }
2684         result = autocomplete_param_with_ac(input, "/plugins reload", plugins_reload_ac, TRUE, previous);
2685         if (result) {
2686             return result;
2687         }
2688     }
2689 
2690     if (strncmp(input, "/plugins unload ", 16) == 0) {
2691         if (plugins_unload_ac == NULL) {
2692             plugins_unload_ac = autocomplete_new();
2693             GList* plugins = plugins_loaded_list();
2694             GList* curr = plugins;
2695             while (curr) {
2696                 autocomplete_add(plugins_unload_ac, curr->data);
2697                 curr = g_list_next(curr);
2698             }
2699             g_list_free(plugins);
2700         }
2701         result = autocomplete_param_with_ac(input, "/plugins unload", plugins_unload_ac, TRUE, previous);
2702         if (result) {
2703             return result;
2704         }
2705     }
2706 
2707     result = autocomplete_param_with_ac(input, "/plugins", plugins_ac, TRUE, previous);
2708     if (result) {
2709         return result;
2710     }
2711 
2712     return NULL;
2713 }
2714 
2715 static char*
_theme_autocomplete(ProfWin * window,const char * const input,gboolean previous)2716 _theme_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2717 {
2718     char* result = NULL;
2719 
2720     if (strncmp(input, "/theme load ", 12) == 0) {
2721         if (theme_load_ac == NULL) {
2722             theme_load_ac = autocomplete_new();
2723             GSList* themes = theme_list();
2724             GSList* curr = themes;
2725 
2726             while (curr) {
2727                 autocomplete_add(theme_load_ac, curr->data);
2728                 curr = g_slist_next(curr);
2729             }
2730 
2731             g_slist_free_full(themes, g_free);
2732             autocomplete_add(theme_load_ac, "default");
2733         }
2734 
2735         result = autocomplete_param_with_ac(input, "/theme load", theme_load_ac, TRUE, previous);
2736         if (result) {
2737             return result;
2738         }
2739     }
2740 
2741     if (strncmp(input, "/theme full-load ", 17) == 0) {
2742         if (theme_load_ac == NULL) {
2743             theme_load_ac = autocomplete_new();
2744             GSList* themes = theme_list();
2745             GSList* curr = themes;
2746 
2747             while (curr) {
2748                 autocomplete_add(theme_load_ac, curr->data);
2749                 curr = g_slist_next(curr);
2750             }
2751 
2752             g_slist_free_full(themes, g_free);
2753             autocomplete_add(theme_load_ac, "default");
2754         }
2755 
2756         result = autocomplete_param_with_ac(input, "/theme full-load", theme_load_ac, TRUE, previous);
2757         if (result) {
2758             return result;
2759         }
2760     }
2761 
2762     result = autocomplete_param_with_ac(input, "/theme", theme_ac, TRUE, previous);
2763     if (result) {
2764         return result;
2765     }
2766 
2767     return NULL;
2768 }
2769 
2770 static char*
_script_autocomplete_func(const char * const prefix,gboolean previous,void * context)2771 _script_autocomplete_func(const char* const prefix, gboolean previous, void* context)
2772 {
2773     if (script_show_ac == NULL) {
2774         script_show_ac = autocomplete_new();
2775         GSList* scripts = scripts_list();
2776         GSList* curr = scripts;
2777         while (curr) {
2778             autocomplete_add(script_show_ac, curr->data);
2779             curr = g_slist_next(curr);
2780         }
2781         g_slist_free_full(scripts, g_free);
2782     }
2783 
2784     return autocomplete_complete(script_show_ac, prefix, FALSE, previous);
2785 }
2786 
2787 static char*
_script_autocomplete(ProfWin * window,const char * const input,gboolean previous)2788 _script_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2789 {
2790     char* result = NULL;
2791     if (strncmp(input, "/script show ", 13) == 0) {
2792         result = autocomplete_param_with_func(input, "/script show", _script_autocomplete_func, previous, NULL);
2793         if (result) {
2794             return result;
2795         }
2796     }
2797 
2798     if (strncmp(input, "/script run ", 12) == 0) {
2799         result = autocomplete_param_with_func(input, "/script run", _script_autocomplete_func, previous, NULL);
2800         if (result) {
2801             return result;
2802         }
2803     }
2804 
2805     result = autocomplete_param_with_ac(input, "/script", script_ac, TRUE, previous);
2806     if (result) {
2807         return result;
2808     }
2809 
2810     return NULL;
2811 }
2812 
2813 static char*
_resource_autocomplete(ProfWin * window,const char * const input,gboolean previous)2814 _resource_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2815 {
2816     char* found = NULL;
2817 
2818     jabber_conn_status_t conn_status = connection_get_status();
2819     if (conn_status == JABBER_CONNECTED && window->type == WIN_CHAT) {
2820         ProfChatWin* chatwin = (ProfChatWin*)window;
2821         assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
2822         PContact contact = roster_get_contact(chatwin->barejid);
2823         if (contact) {
2824             Autocomplete ac = p_contact_resource_ac(contact);
2825             found = autocomplete_param_with_ac(input, "/resource set", ac, FALSE, previous);
2826             if (found) {
2827                 return found;
2828             }
2829         }
2830     }
2831 
2832     found = autocomplete_param_with_func(input, "/resource title", prefs_autocomplete_boolean_choice, previous, NULL);
2833     if (found) {
2834         return found;
2835     }
2836 
2837     found = autocomplete_param_with_func(input, "/resource message", prefs_autocomplete_boolean_choice, previous, NULL);
2838     if (found) {
2839         return found;
2840     }
2841 
2842     found = autocomplete_param_with_ac(input, "/resource", resource_ac, FALSE, previous);
2843     if (found) {
2844         return found;
2845     }
2846 
2847     return NULL;
2848 }
2849 
2850 static char*
_wintitle_autocomplete(ProfWin * window,const char * const input,gboolean previous)2851 _wintitle_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2852 {
2853     char* found = NULL;
2854 
2855     found = autocomplete_param_with_func(input, "/wintitle show", prefs_autocomplete_boolean_choice, previous, NULL);
2856     if (found) {
2857         return found;
2858     }
2859 
2860     found = autocomplete_param_with_func(input, "/wintitle goodbye", prefs_autocomplete_boolean_choice, previous, NULL);
2861     if (found) {
2862         return found;
2863     }
2864 
2865     found = autocomplete_param_with_ac(input, "/wintitle", wintitle_ac, FALSE, previous);
2866     if (found) {
2867         return found;
2868     }
2869 
2870     return NULL;
2871 }
2872 
2873 static char*
_inpblock_autocomplete(ProfWin * window,const char * const input,gboolean previous)2874 _inpblock_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2875 {
2876     char* found = NULL;
2877 
2878     found = autocomplete_param_with_func(input, "/inpblock dynamic", prefs_autocomplete_boolean_choice, previous, NULL);
2879     if (found) {
2880         return found;
2881     }
2882 
2883     found = autocomplete_param_with_ac(input, "/inpblock", inpblock_ac, FALSE, previous);
2884     if (found) {
2885         return found;
2886     }
2887 
2888     return NULL;
2889 }
2890 
2891 static char*
_form_autocomplete(ProfWin * window,const char * const input,gboolean previous)2892 _form_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2893 {
2894     if (window->type != WIN_CONFIG) {
2895         return NULL;
2896     }
2897 
2898     char* found = NULL;
2899 
2900     ProfConfWin* confwin = (ProfConfWin*)window;
2901     DataForm* form = confwin->form;
2902     if (form) {
2903         found = autocomplete_param_with_ac(input, "/form help", form->tag_ac, TRUE, previous);
2904         if (found) {
2905             return found;
2906         }
2907     }
2908 
2909     found = autocomplete_param_with_ac(input, "/form", form_ac, TRUE, previous);
2910     if (found) {
2911         return found;
2912     }
2913 
2914     return NULL;
2915 }
2916 
2917 static char*
_form_field_autocomplete(ProfWin * window,const char * const input,gboolean previous)2918 _form_field_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2919 {
2920     if (window->type != WIN_CONFIG) {
2921         return NULL;
2922     }
2923 
2924     char* found = NULL;
2925 
2926     ProfConfWin* confwin = (ProfConfWin*)window;
2927     DataForm* form = confwin->form;
2928     if (form == NULL) {
2929         return NULL;
2930     }
2931 
2932     gchar** split = g_strsplit(input, " ", 0);
2933 
2934     if (g_strv_length(split) == 3) {
2935         char* field_tag = split[0] + 1;
2936         if (form_tag_exists(form, field_tag)) {
2937             form_field_type_t field_type = form_get_field_type(form, field_tag);
2938             Autocomplete value_ac = form_get_value_ac(form, field_tag);
2939             ;
2940             GString* beginning = g_string_new(split[0]);
2941             g_string_append(beginning, " ");
2942             g_string_append(beginning, split[1]);
2943 
2944             if (((g_strcmp0(split[1], "add") == 0) || (g_strcmp0(split[1], "remove") == 0))
2945                 && field_type == FIELD_LIST_MULTI) {
2946                 found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE, previous);
2947 
2948             } else if ((g_strcmp0(split[1], "remove") == 0) && field_type == FIELD_TEXT_MULTI) {
2949                 found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE, previous);
2950 
2951             } else if ((g_strcmp0(split[1], "remove") == 0) && field_type == FIELD_JID_MULTI) {
2952                 found = autocomplete_param_with_ac(input, beginning->str, value_ac, TRUE, previous);
2953             }
2954 
2955             g_string_free(beginning, TRUE);
2956         }
2957 
2958     } else if (g_strv_length(split) == 2) {
2959         char* field_tag = split[0] + 1;
2960         if (form_tag_exists(form, field_tag)) {
2961             form_field_type_t field_type = form_get_field_type(form, field_tag);
2962             Autocomplete value_ac = form_get_value_ac(form, field_tag);
2963             ;
2964 
2965             switch (field_type) {
2966             case FIELD_BOOLEAN:
2967                 found = autocomplete_param_with_func(input, split[0], prefs_autocomplete_boolean_choice, previous, NULL);
2968                 break;
2969             case FIELD_LIST_SINGLE:
2970                 found = autocomplete_param_with_ac(input, split[0], value_ac, TRUE, previous);
2971                 break;
2972             case FIELD_LIST_MULTI:
2973             case FIELD_JID_MULTI:
2974             case FIELD_TEXT_MULTI:
2975                 found = autocomplete_param_with_ac(input, split[0], form_field_multi_ac, TRUE, previous);
2976                 break;
2977             default:
2978                 break;
2979             }
2980         }
2981     }
2982 
2983     g_strfreev(split);
2984 
2985     return found;
2986 }
2987 
2988 static char*
_occupants_autocomplete(ProfWin * window,const char * const input,gboolean previous)2989 _occupants_autocomplete(ProfWin* window, const char* const input, gboolean previous)
2990 {
2991     char* found = NULL;
2992 
2993     found = autocomplete_param_with_ac(input, "/occupants default show", occupants_show_ac, TRUE, previous);
2994     if (found) {
2995         return found;
2996     }
2997 
2998     found = autocomplete_param_with_ac(input, "/occupants char", occupants_char_ac, TRUE, previous);
2999     if (found) {
3000         return found;
3001     }
3002 
3003     found = autocomplete_param_with_func(input, "/occupants color", prefs_autocomplete_boolean_choice, previous, NULL);
3004     if (found) {
3005         return found;
3006     }
3007 
3008     found = autocomplete_param_with_ac(input, "/occupants default hide", occupants_show_ac, TRUE, previous);
3009     if (found) {
3010         return found;
3011     }
3012 
3013     found = autocomplete_param_with_ac(input, "/occupants default", occupants_default_ac, TRUE, previous);
3014     if (found) {
3015         return found;
3016     }
3017 
3018     found = autocomplete_param_with_ac(input, "/occupants show", occupants_show_ac, TRUE, previous);
3019     if (found) {
3020         return found;
3021     }
3022 
3023     found = autocomplete_param_with_ac(input, "/occupants hide", occupants_show_ac, TRUE, previous);
3024     if (found) {
3025         return found;
3026     }
3027 
3028     found = autocomplete_param_with_ac(input, "/occupants header char", roster_char_ac, TRUE, previous);
3029     if (found) {
3030         return found;
3031     }
3032 
3033     found = autocomplete_param_with_ac(input, "/occupants header", occupants_header_ac, TRUE, previous);
3034     if (found) {
3035         return found;
3036     }
3037 
3038     found = autocomplete_param_with_func(input, "/occupants wrap", prefs_autocomplete_boolean_choice, previous, NULL);
3039     if (found) {
3040         return found;
3041     }
3042 
3043     found = autocomplete_param_with_ac(input, "/occupants", occupants_ac, TRUE, previous);
3044     if (found) {
3045         return found;
3046     }
3047 
3048     return NULL;
3049 }
3050 
3051 static char*
_time_autocomplete(ProfWin * window,const char * const input,gboolean previous)3052 _time_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3053 {
3054     char* found = NULL;
3055 
3056     found = autocomplete_param_with_ac(input, "/time statusbar", time_format_ac, TRUE, previous);
3057     if (found) {
3058         return found;
3059     }
3060 
3061     found = autocomplete_param_with_ac(input, "/time lastactivity", time_format_ac, TRUE, previous);
3062     if (found) {
3063         return found;
3064     }
3065 
3066     found = autocomplete_param_with_ac(input, "/time console", time_format_ac, TRUE, previous);
3067     if (found) {
3068         return found;
3069     }
3070 
3071     found = autocomplete_param_with_ac(input, "/time chat", time_format_ac, TRUE, previous);
3072     if (found) {
3073         return found;
3074     }
3075 
3076     found = autocomplete_param_with_ac(input, "/time muc", time_format_ac, TRUE, previous);
3077     if (found) {
3078         return found;
3079     }
3080 
3081     found = autocomplete_param_with_ac(input, "/time config", time_format_ac, TRUE, previous);
3082     if (found) {
3083         return found;
3084     }
3085 
3086     found = autocomplete_param_with_ac(input, "/time private", time_format_ac, TRUE, previous);
3087     if (found) {
3088         return found;
3089     }
3090 
3091     found = autocomplete_param_with_ac(input, "/time xml", time_format_ac, TRUE, previous);
3092     if (found) {
3093         return found;
3094     }
3095 
3096     found = autocomplete_param_with_ac(input, "/time all", time_format_ac, TRUE, previous);
3097     if (found) {
3098         return found;
3099     }
3100 
3101     found = autocomplete_param_with_ac(input, "/time", time_ac, TRUE, previous);
3102     if (found) {
3103         return found;
3104     }
3105 
3106     return NULL;
3107 }
3108 
3109 static char*
_kick_autocomplete(ProfWin * window,const char * const input,gboolean previous)3110 _kick_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3111 {
3112     if (window->type != WIN_MUC) {
3113         return NULL;
3114     }
3115 
3116     ProfMucWin* mucwin = (ProfMucWin*)window;
3117     assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
3118     Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
3119     if (nick_ac == NULL) {
3120         return NULL;
3121     }
3122 
3123     char* result = autocomplete_param_with_ac(input, "/kick", nick_ac, TRUE, previous);
3124 
3125     return result;
3126 }
3127 
3128 static char*
_ban_autocomplete(ProfWin * window,const char * const input,gboolean previous)3129 _ban_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3130 {
3131     if (window->type != WIN_MUC) {
3132         return NULL;
3133     }
3134 
3135     ProfMucWin* mucwin = (ProfMucWin*)window;
3136     assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
3137     Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid);
3138     if (jid_ac == NULL) {
3139         return NULL;
3140     }
3141 
3142     char* result = autocomplete_param_with_ac(input, "/ban", jid_ac, TRUE, previous);
3143 
3144     return result;
3145 }
3146 
3147 static char*
_affiliation_autocomplete(ProfWin * window,const char * const input,gboolean previous)3148 _affiliation_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3149 {
3150     char* result = NULL;
3151 
3152     if (window->type == WIN_MUC) {
3153         ProfMucWin* mucwin = (ProfMucWin*)window;
3154         assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
3155         gboolean parse_result;
3156         Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid);
3157 
3158         gchar** args = parse_args(input, 2, 3, &parse_result);
3159 
3160         if ((strncmp(input, "/affiliation", 12) == 0) && (parse_result == TRUE)) {
3161             GString* beginning = g_string_new("/affiliation ");
3162             g_string_append(beginning, args[0]);
3163             g_string_append(beginning, " ");
3164             if (args[1]) {
3165                 g_string_append(beginning, args[1]);
3166             }
3167 
3168             result = autocomplete_param_with_ac(input, beginning->str, jid_ac, TRUE, previous);
3169             g_string_free(beginning, TRUE);
3170             if (result) {
3171                 g_strfreev(args);
3172                 return result;
3173             }
3174         }
3175 
3176         g_strfreev(args);
3177     }
3178 
3179     result = autocomplete_param_with_ac(input, "/affiliation set", affiliation_ac, TRUE, previous);
3180     if (result) {
3181         return result;
3182     }
3183 
3184     result = autocomplete_param_with_ac(input, "/affiliation list", affiliation_ac, TRUE, previous);
3185     if (result) {
3186         return result;
3187     }
3188 
3189     result = autocomplete_param_with_ac(input, "/affiliation", affiliation_cmd_ac, TRUE, previous);
3190 
3191     return result;
3192 }
3193 
3194 static char*
_role_autocomplete(ProfWin * window,const char * const input,gboolean previous)3195 _role_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3196 {
3197     char* result = NULL;
3198 
3199     if (window->type == WIN_MUC) {
3200         ProfMucWin* mucwin = (ProfMucWin*)window;
3201         assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
3202         gboolean parse_result;
3203         Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
3204 
3205         gchar** args = parse_args(input, 2, 3, &parse_result);
3206 
3207         if ((strncmp(input, "/role", 5) == 0) && (parse_result == TRUE)) {
3208             GString* beginning = g_string_new("/role ");
3209             g_string_append(beginning, args[0]);
3210             g_string_append(beginning, " ");
3211             if (args[1]) {
3212                 g_string_append(beginning, args[1]);
3213             }
3214 
3215             result = autocomplete_param_with_ac(input, beginning->str, nick_ac, TRUE, previous);
3216             g_string_free(beginning, TRUE);
3217             if (result) {
3218                 g_strfreev(args);
3219                 return result;
3220             }
3221         }
3222 
3223         g_strfreev(args);
3224     }
3225 
3226     result = autocomplete_param_with_ac(input, "/role set", role_ac, TRUE, previous);
3227     if (result) {
3228         return result;
3229     }
3230 
3231     result = autocomplete_param_with_ac(input, "/role list", role_ac, TRUE, previous);
3232     if (result) {
3233         return result;
3234     }
3235 
3236     result = autocomplete_param_with_ac(input, "/role", role_cmd_ac, TRUE, previous);
3237 
3238     return result;
3239 }
3240 
3241 static char*
_wins_autocomplete(ProfWin * window,const char * const input,gboolean previous)3242 _wins_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3243 {
3244     char* result = NULL;
3245 
3246     result = autocomplete_param_with_ac(input, "/wins", wins_ac, TRUE, previous);
3247 
3248     return result;
3249 }
3250 
3251 static char*
_tls_autocomplete(ProfWin * window,const char * const input,gboolean previous)3252 _tls_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3253 {
3254     char* result = NULL;
3255 
3256     result = autocomplete_param_with_func(input, "/tls revoke", tlscerts_complete, previous, NULL);
3257     if (result) {
3258         return result;
3259     }
3260 
3261     result = autocomplete_param_with_func(input, "/tls cert", tlscerts_complete, previous, NULL);
3262     if (result) {
3263         return result;
3264     }
3265 
3266     result = autocomplete_param_with_ac(input, "/tls certpath", tls_certpath_ac, TRUE, previous);
3267     if (result) {
3268         return result;
3269     }
3270 
3271     result = autocomplete_param_with_ac(input, "/tls", tls_ac, TRUE, previous);
3272 
3273     return result;
3274 }
3275 
3276 static char*
_titlebar_autocomplete(ProfWin * window,const char * const input,gboolean previous)3277 _titlebar_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3278 {
3279     char* result = NULL;
3280 
3281     result = autocomplete_param_with_ac(input, "/titlebar show", titlebar_show_ac, TRUE, previous);
3282     if (result) {
3283         return result;
3284     }
3285 
3286     result = autocomplete_param_with_ac(input, "/titlebar hide", titlebar_show_ac, TRUE, previous);
3287     if (result) {
3288         return result;
3289     }
3290 
3291     result = autocomplete_param_with_ac(input, "/titlebar", titlebar_ac, TRUE, previous);
3292 
3293     return result;
3294 }
3295 
3296 static char*
_receipts_autocomplete(ProfWin * window,const char * const input,gboolean previous)3297 _receipts_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3298 {
3299     char* result = NULL;
3300 
3301     result = autocomplete_param_with_func(input, "/receipts send", prefs_autocomplete_boolean_choice, previous, NULL);
3302     if (result) {
3303         return result;
3304     }
3305 
3306     result = autocomplete_param_with_func(input, "/receipts request", prefs_autocomplete_boolean_choice, previous, NULL);
3307     if (result) {
3308         return result;
3309     }
3310 
3311     result = autocomplete_param_with_ac(input, "/receipts", receipts_ac, TRUE, previous);
3312 
3313     return result;
3314 }
3315 
3316 static char*
_alias_autocomplete(ProfWin * window,const char * const input,gboolean previous)3317 _alias_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3318 {
3319     char* result = NULL;
3320 
3321     result = autocomplete_param_with_ac(input, "/alias remove", aliases_ac, TRUE, previous);
3322     if (result) {
3323         return result;
3324     }
3325 
3326     result = autocomplete_param_with_ac(input, "/alias", alias_ac, TRUE, previous);
3327 
3328     return result;
3329 }
3330 
3331 static char*
_connect_autocomplete(ProfWin * window,const char * const input,gboolean previous)3332 _connect_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3333 {
3334     char* found = NULL;
3335     gboolean result = FALSE;
3336 
3337     gchar** args = parse_args(input, 1, 9, &result);
3338 
3339     if (result) {
3340         gboolean space_at_end = g_str_has_suffix(input, " ");
3341         int num_args = g_strv_length(args);
3342         if ((num_args == 1 && space_at_end) || (num_args == 2 && !space_at_end)) {
3343             GString* beginning = g_string_new("/connect");
3344             g_string_append_printf(beginning, " %s", args[0]);
3345             found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE, previous);
3346             g_string_free(beginning, TRUE);
3347             if (found) {
3348                 g_strfreev(args);
3349                 return found;
3350             }
3351         }
3352         if ((num_args == 2 && space_at_end && (g_strcmp0(args[1], "tls") == 0))
3353             || (num_args == 3 && (g_strcmp0(args[1], "tls") == 0) && !space_at_end)) {
3354             GString* beginning = g_string_new("/connect");
3355             g_string_append_printf(beginning, " %s %s", args[0], args[1]);
3356             found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
3357             g_string_free(beginning, TRUE);
3358             if (found) {
3359                 g_strfreev(args);
3360                 return found;
3361             }
3362         }
3363         if ((num_args == 3 && space_at_end) || (num_args == 4 && !space_at_end)) {
3364             GString* beginning = g_string_new("/connect");
3365             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
3366             found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE, previous);
3367             g_string_free(beginning, TRUE);
3368             if (found) {
3369                 g_strfreev(args);
3370                 return found;
3371             }
3372         }
3373         if ((num_args == 4 && space_at_end && (g_strcmp0(args[3], "tls") == 0))
3374             || (num_args == 5 && (g_strcmp0(args[3], "tls") == 0) && !space_at_end)) {
3375             GString* beginning = g_string_new("/connect");
3376             g_string_append_printf(beginning, " %s %s %s %s", args[0], args[1], args[2], args[3]);
3377             found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
3378             g_string_free(beginning, TRUE);
3379             if (found) {
3380                 g_strfreev(args);
3381                 return found;
3382             }
3383         }
3384         if ((num_args == 5 && space_at_end) || (num_args == 6 && !space_at_end)) {
3385             GString* beginning = g_string_new("/connect");
3386             g_string_append_printf(beginning, " %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4]);
3387             found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE, previous);
3388             g_string_free(beginning, TRUE);
3389             if (found) {
3390                 g_strfreev(args);
3391                 return found;
3392             }
3393         }
3394         if ((num_args == 6 && space_at_end && (g_strcmp0(args[5], "tls") == 0))
3395             || (num_args == 7 && (g_strcmp0(args[5], "tls") == 0) && !space_at_end)) {
3396             GString* beginning = g_string_new("/connect");
3397             g_string_append_printf(beginning, " %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5]);
3398             found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
3399             g_string_free(beginning, TRUE);
3400             if (found) {
3401                 g_strfreev(args);
3402                 return found;
3403             }
3404         }
3405         if ((num_args == 7 && space_at_end) || (num_args == 8 && !space_at_end)) {
3406             GString* beginning = g_string_new("/connect");
3407             g_string_append_printf(beginning, " %s %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
3408             found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE, previous);
3409             g_string_free(beginning, TRUE);
3410             if (found) {
3411                 g_strfreev(args);
3412                 return found;
3413             }
3414         }
3415         if ((num_args == 8 && space_at_end && (g_strcmp0(args[7], "tls") == 0))
3416             || (num_args == 9 && (g_strcmp0(args[7], "tls") == 0) && !space_at_end)) {
3417             GString* beginning = g_string_new("/connect");
3418             g_string_append_printf(beginning, " %s %s %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
3419             found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
3420             g_string_free(beginning, TRUE);
3421             if (found) {
3422                 g_strfreev(args);
3423                 return found;
3424             }
3425         }
3426 
3427         /* auth option */
3428 
3429         if ((num_args == 2 && space_at_end && (g_strcmp0(args[1], "auth") == 0))
3430             || (num_args == 3 && (g_strcmp0(args[1], "auth") == 0) && !space_at_end)) {
3431             GString* beginning = g_string_new("/connect");
3432             g_string_append_printf(beginning, " %s %s", args[0], args[1]);
3433             found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
3434             g_string_free(beginning, TRUE);
3435             if (found) {
3436                 g_strfreev(args);
3437                 return found;
3438             }
3439         }
3440         if ((num_args == 4 && space_at_end && (g_strcmp0(args[3], "auth") == 0))
3441             || (num_args == 5 && (g_strcmp0(args[3], "auth") == 0) && !space_at_end)) {
3442             GString* beginning = g_string_new("/connect");
3443             g_string_append_printf(beginning, " %s %s %s %s", args[0], args[1], args[2], args[3]);
3444             found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
3445             g_string_free(beginning, TRUE);
3446             if (found) {
3447                 g_strfreev(args);
3448                 return found;
3449             }
3450         }
3451         if ((num_args == 6 && space_at_end && (g_strcmp0(args[5], "auth") == 0))
3452             || (num_args == 7 && (g_strcmp0(args[5], "auth") == 0) && !space_at_end)) {
3453             GString* beginning = g_string_new("/connect");
3454             g_string_append_printf(beginning, " %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5]);
3455             found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
3456             g_string_free(beginning, TRUE);
3457             if (found) {
3458                 g_strfreev(args);
3459                 return found;
3460             }
3461         }
3462         if ((num_args == 8 && space_at_end && (g_strcmp0(args[7], "auth") == 0))
3463             || (num_args == 9 && (g_strcmp0(args[7], "auth") == 0) && !space_at_end)) {
3464             GString* beginning = g_string_new("/connect");
3465             g_string_append_printf(beginning, " %s %s %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
3466             found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
3467             g_string_free(beginning, TRUE);
3468             if (found) {
3469                 g_strfreev(args);
3470                 return found;
3471             }
3472         }
3473     }
3474 
3475     g_strfreev(args);
3476 
3477     found = autocomplete_param_with_func(input, "/connect", accounts_find_enabled, previous, NULL);
3478     if (found) {
3479         return found;
3480     }
3481 
3482     return NULL;
3483 }
3484 
3485 static char*
_help_autocomplete(ProfWin * window,const char * const input,gboolean previous)3486 _help_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3487 {
3488     char* result = NULL;
3489 
3490     result = autocomplete_param_with_ac(input, "/help commands", help_commands_ac, TRUE, previous);
3491     if (result) {
3492         return result;
3493     }
3494 
3495     result = autocomplete_param_with_ac(input, "/help", help_ac, TRUE, previous);
3496     return result;
3497 }
3498 
3499 static char*
_join_autocomplete(ProfWin * window,const char * const input,gboolean previous)3500 _join_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3501 {
3502     char* found = NULL;
3503     gboolean result = FALSE;
3504 
3505     gchar** args = parse_args(input, 1, 5, &result);
3506 
3507     if (result) {
3508         gboolean space_at_end = g_str_has_suffix(input, " ");
3509         int num_args = g_strv_length(args);
3510         if ((num_args == 1 && space_at_end) || (num_args == 2 && !space_at_end)) {
3511             GString* beginning = g_string_new("/join");
3512             g_string_append_printf(beginning, " %s", args[0]);
3513             found = autocomplete_param_with_ac(input, beginning->str, join_property_ac, TRUE, previous);
3514             g_string_free(beginning, TRUE);
3515             if (found) {
3516                 g_strfreev(args);
3517                 return found;
3518             }
3519         }
3520         if ((num_args == 3 && space_at_end) || (num_args == 4 && !space_at_end)) {
3521             GString* beginning = g_string_new("/join");
3522             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
3523             found = autocomplete_param_with_ac(input, beginning->str, join_property_ac, TRUE, previous);
3524             g_string_free(beginning, TRUE);
3525             if (found) {
3526                 g_strfreev(args);
3527                 return found;
3528             }
3529         }
3530     }
3531 
3532     g_strfreev(args);
3533 
3534     found = autocomplete_param_with_func(input, "/join", bookmark_find, previous, NULL);
3535 
3536     return found;
3537 }
3538 
3539 static char*
_console_autocomplete(ProfWin * window,const char * const input,gboolean previous)3540 _console_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3541 {
3542     char* result = NULL;
3543 
3544     result = autocomplete_param_with_ac(input, "/console chat", console_msg_ac, TRUE, previous);
3545     if (result) {
3546         return result;
3547     }
3548     result = autocomplete_param_with_ac(input, "/console muc", console_msg_ac, TRUE, previous);
3549     if (result) {
3550         return result;
3551     }
3552     result = autocomplete_param_with_ac(input, "/console private", console_msg_ac, TRUE, previous);
3553     if (result) {
3554         return result;
3555     }
3556 
3557     result = autocomplete_param_with_ac(input, "/console", console_ac, TRUE, previous);
3558     return result;
3559 }
3560 
3561 static char*
_win_autocomplete(ProfWin * window,const char * const input,gboolean previous)3562 _win_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3563 {
3564     return autocomplete_param_with_func(input, "/win", win_autocomplete, previous, NULL);
3565 }
3566 
3567 static char*
_close_autocomplete(ProfWin * window,const char * const input,gboolean previous)3568 _close_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3569 {
3570     return autocomplete_param_with_func(input, "/close", win_close_autocomplete, previous, NULL);
3571 }
3572 
3573 static char*
_sendfile_autocomplete(ProfWin * window,const char * const input,gboolean previous)3574 _sendfile_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3575 {
3576     return cmd_ac_complete_filepath(input, "/sendfile", previous);
3577 }
3578 
3579 static char*
_subject_autocomplete(ProfWin * window,const char * const input,gboolean previous)3580 _subject_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3581 {
3582     char* result = NULL;
3583 
3584     if (window->type == WIN_MUC) {
3585         if ((g_strcmp0(input, "/subject e") == 0)
3586             || (g_strcmp0(input, "/subject ed") == 0)
3587             || (g_strcmp0(input, "/subject edi") == 0)
3588             || (g_strcmp0(input, "/subject edit") == 0)
3589             || (g_strcmp0(input, "/subject edit ") == 0)
3590             || (g_strcmp0(input, "/subject edit \"") == 0)) {
3591             ProfMucWin* mucwin = (ProfMucWin*)window;
3592             assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
3593 
3594             char* subject = muc_subject(mucwin->roomjid);
3595             if (subject) {
3596                 GString* result_str = g_string_new("/subject edit \"");
3597                 g_string_append(result_str, subject);
3598                 g_string_append(result_str, "\"");
3599 
3600                 result = result_str->str;
3601                 g_string_free(result_str, FALSE);
3602             }
3603         }
3604     }
3605     if (result) {
3606         return result;
3607     }
3608 
3609     result = autocomplete_param_with_ac(input, "/subject", subject_ac, TRUE, previous);
3610 
3611     return result;
3612 }
3613 
3614 static char*
_account_autocomplete(ProfWin * window,const char * const input,gboolean previous)3615 _account_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3616 {
3617     char* found = NULL;
3618     gboolean result = FALSE;
3619 
3620     gchar** args = parse_args(input, 2, 4, &result);
3621     if (result && (strcmp(args[0], "set") == 0)) {
3622         gboolean space_at_end = g_str_has_suffix(input, " ");
3623         int num_args = g_strv_length(args);
3624         if ((num_args == 2 && space_at_end) || (num_args == 3 && !space_at_end)) {
3625             GString* beginning = g_string_new("/account");
3626             g_string_append_printf(beginning, " %s %s", args[0], args[1]);
3627             found = autocomplete_param_with_ac(input, beginning->str, account_set_ac, TRUE, previous);
3628             g_string_free(beginning, TRUE);
3629             if (found) {
3630                 g_strfreev(args);
3631                 return found;
3632             }
3633         }
3634 #ifdef HAVE_LIBOTR
3635         if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "otr") == 0))
3636             || (num_args == 4 && (g_strcmp0(args[2], "otr") == 0) && !space_at_end)) {
3637             GString* beginning = g_string_new("/account");
3638             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
3639             found = autocomplete_param_with_ac(input, beginning->str, otr_policy_ac, TRUE, previous);
3640             g_string_free(beginning, TRUE);
3641             if (found) {
3642                 g_strfreev(args);
3643                 return found;
3644             }
3645         }
3646 #endif
3647         if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "status") == 0))
3648             || (num_args == 4 && (g_strcmp0(args[2], "status") == 0) && !space_at_end)) {
3649             GString* beginning = g_string_new("/account");
3650             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
3651             found = autocomplete_param_with_ac(input, beginning->str, account_status_ac, TRUE, previous);
3652             g_string_free(beginning, TRUE);
3653             if (found) {
3654                 g_strfreev(args);
3655                 return found;
3656             }
3657         }
3658         if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "tls") == 0))
3659             || (num_args == 4 && (g_strcmp0(args[2], "tls") == 0) && !space_at_end)) {
3660             GString* beginning = g_string_new("/account");
3661             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
3662             found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
3663             g_string_free(beginning, TRUE);
3664             if (found) {
3665                 g_strfreev(args);
3666                 return found;
3667             }
3668         }
3669         if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "auth") == 0))
3670             || (num_args == 4 && (g_strcmp0(args[2], "auth") == 0) && !space_at_end)) {
3671             GString* beginning = g_string_new("/account");
3672             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
3673             found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
3674             g_string_free(beginning, TRUE);
3675             if (found) {
3676                 g_strfreev(args);
3677                 return found;
3678             }
3679         }
3680         if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "startscript") == 0))
3681             || (num_args == 4 && (g_strcmp0(args[2], "startscript") == 0) && !space_at_end)) {
3682             GString* beginning = g_string_new("/account");
3683             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
3684             found = autocomplete_param_with_func(input, beginning->str, _script_autocomplete_func, previous, NULL);
3685             g_string_free(beginning, TRUE);
3686             if (found) {
3687                 g_strfreev(args);
3688                 return found;
3689             }
3690         }
3691         if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "theme") == 0))
3692             || (num_args == 4 && (g_strcmp0(args[2], "theme") == 0) && !space_at_end)) {
3693             GString* beginning = g_string_new("/account");
3694             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
3695             if (theme_load_ac == NULL) {
3696                 theme_load_ac = autocomplete_new();
3697                 GSList* themes = theme_list();
3698                 GSList* curr = themes;
3699                 while (curr) {
3700                     autocomplete_add(theme_load_ac, curr->data);
3701                     curr = g_slist_next(curr);
3702                 }
3703                 g_slist_free_full(themes, g_free);
3704                 autocomplete_add(theme_load_ac, "default");
3705             }
3706             found = autocomplete_param_with_ac(input, beginning->str, theme_load_ac, TRUE, previous);
3707             g_string_free(beginning, TRUE);
3708             if (found) {
3709                 g_strfreev(args);
3710                 return found;
3711             }
3712         }
3713 #ifdef HAVE_LIBGPGME
3714         if ((num_args == 3 && space_at_end && (g_strcmp0(args[2], "pgpkeyid") == 0))
3715             || (num_args == 4 && (g_strcmp0(args[2], "pgpkeyid") == 0) && !space_at_end)) {
3716             GString* beginning = g_string_new("/account");
3717             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
3718             found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous, NULL);
3719             g_string_free(beginning, TRUE);
3720             if (found) {
3721                 g_strfreev(args);
3722                 return found;
3723             }
3724         }
3725 #endif
3726     }
3727 
3728     if ((strncmp(input, "/account clear", 14) == 0) && (result == TRUE)) {
3729         GString* beginning = g_string_new("/account clear ");
3730         g_string_append(beginning, args[1]);
3731         found = autocomplete_param_with_ac(input, beginning->str, account_clear_ac, TRUE, previous);
3732         g_string_free(beginning, TRUE);
3733         if (found) {
3734             g_strfreev(args);
3735             return found;
3736         }
3737     }
3738 
3739     g_strfreev(args);
3740 
3741     found = autocomplete_param_with_ac(input, "/account default", account_default_ac, TRUE, previous);
3742     if (found) {
3743         return found;
3744     }
3745 
3746     gchar* account_choice[] = { "/account set", "/account show", "/account enable",
3747                                 "/account disable", "/account rename", "/account clear", "/account remove",
3748                                 "/account default set" };
3749 
3750     for (int i = 0; i < ARRAY_SIZE(account_choice); i++) {
3751         found = autocomplete_param_with_func(input, account_choice[i], accounts_find_all, previous, NULL);
3752         if (found) {
3753             return found;
3754         }
3755     }
3756 
3757     found = autocomplete_param_with_ac(input, "/account", account_ac, TRUE, previous);
3758     return found;
3759 }
3760 
3761 static char*
_presence_autocomplete(ProfWin * window,const char * const input,gboolean previous)3762 _presence_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3763 {
3764     char* found = NULL;
3765 
3766     found = autocomplete_param_with_func(input, "/presence titlebar", prefs_autocomplete_boolean_choice, previous, NULL);
3767     if (found) {
3768         return found;
3769     }
3770 
3771     found = autocomplete_param_with_ac(input, "/presence console", presence_setting_ac, TRUE, previous);
3772     if (found) {
3773         return found;
3774     }
3775 
3776     found = autocomplete_param_with_ac(input, "/presence chat", presence_setting_ac, TRUE, previous);
3777     if (found) {
3778         return found;
3779     }
3780 
3781     found = autocomplete_param_with_ac(input, "/presence room", presence_setting_ac, TRUE, previous);
3782     if (found) {
3783         return found;
3784     }
3785 
3786     found = autocomplete_param_with_ac(input, "/presence", presence_ac, TRUE, previous);
3787 
3788     return found;
3789 }
3790 
3791 static char*
_rooms_autocomplete(ProfWin * window,const char * const input,gboolean previous)3792 _rooms_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3793 {
3794     char* found = NULL;
3795     gboolean result = FALSE;
3796 
3797     gchar** args = parse_args(input, 0, 4, &result);
3798 
3799     if (result) {
3800         gboolean space_at_end = g_str_has_suffix(input, " ");
3801         int num_args = g_strv_length(args);
3802         if (num_args <= 1) {
3803             found = autocomplete_param_with_ac(input, "/rooms", rooms_all_ac, TRUE, previous);
3804             if (found) {
3805                 g_strfreev(args);
3806                 return found;
3807             }
3808         }
3809         if ((num_args == 1 && g_strcmp0(args[0], "service") == 0 && space_at_end) || (num_args == 2 && g_strcmp0(args[0], "service") == 0 && !space_at_end)) {
3810             found = autocomplete_param_with_func(input, "/rooms service", muc_confserver_find, previous, NULL);
3811             if (found) {
3812                 g_strfreev(args);
3813                 return found;
3814             }
3815         }
3816         if ((num_args == 1 && g_strcmp0(args[0], "cache") == 0 && space_at_end) || (num_args == 2 && g_strcmp0(args[0], "cache") == 0 && !space_at_end)) {
3817             found = autocomplete_param_with_ac(input, "/rooms cache", rooms_cache_ac, TRUE, previous);
3818             if (found) {
3819                 g_strfreev(args);
3820                 return found;
3821             }
3822         }
3823         if ((num_args == 2 && space_at_end) || (num_args == 3 && !space_at_end)) {
3824             GString* beginning = g_string_new("/rooms");
3825             g_string_append_printf(beginning, " %s %s", args[0], args[1]);
3826             found = autocomplete_param_with_ac(input, beginning->str, rooms_list_ac, TRUE, previous);
3827             g_string_free(beginning, TRUE);
3828             if (found) {
3829                 g_strfreev(args);
3830                 return found;
3831             }
3832         }
3833         if ((num_args == 3 && g_strcmp0(args[2], "service") == 0 && space_at_end) || (num_args == 4 && g_strcmp0(args[2], "service") == 0 && !space_at_end)) {
3834             GString* beginning = g_string_new("/rooms");
3835             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
3836             found = autocomplete_param_with_func(input, beginning->str, muc_confserver_find, previous, NULL);
3837             g_string_free(beginning, TRUE);
3838             if (found) {
3839                 g_strfreev(args);
3840                 return found;
3841             }
3842         }
3843         if ((num_args >= 2) && g_strcmp0(args[0], "cache") == 0) {
3844             g_strfreev(args);
3845             return NULL;
3846         }
3847     }
3848 
3849     g_strfreev(args);
3850 
3851     return NULL;
3852 }
3853 
3854 static char*
_statusbar_autocomplete(ProfWin * window,const char * const input,gboolean previous)3855 _statusbar_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3856 {
3857     char* found = NULL;
3858 
3859     found = autocomplete_param_with_ac(input, "/statusbar", statusbar_ac, TRUE, previous);
3860     if (found) {
3861         return found;
3862     }
3863 
3864     found = autocomplete_param_with_ac(input, "/statusbar show", statusbar_show_ac, TRUE, previous);
3865     if (found) {
3866         return found;
3867     }
3868 
3869     found = autocomplete_param_with_ac(input, "/statusbar hide", statusbar_show_ac, TRUE, previous);
3870     if (found) {
3871         return found;
3872     }
3873 
3874     found = autocomplete_param_with_ac(input, "/statusbar self", statusbar_self_ac, TRUE, previous);
3875     if (found) {
3876         return found;
3877     }
3878 
3879     found = autocomplete_param_with_ac(input, "/statusbar chat", statusbar_chat_ac, TRUE, previous);
3880     if (found) {
3881         return found;
3882     }
3883 
3884     found = autocomplete_param_with_ac(input, "/statusbar room", statusbar_room_ac, TRUE, previous);
3885 
3886     return found;
3887 }
3888 
3889 static char*
_clear_autocomplete(ProfWin * window,const char * const input,gboolean previous)3890 _clear_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3891 {
3892     char* result = NULL;
3893 
3894     result = autocomplete_param_with_ac(input, "/clear", clear_ac, TRUE, previous);
3895     if (result) {
3896         return result;
3897     }
3898 
3899     result = autocomplete_param_with_func(input, "/clear persist_history", prefs_autocomplete_boolean_choice, previous, NULL);
3900     return result;
3901 }
3902 
3903 static char*
_invite_autocomplete(ProfWin * window,const char * const input,gboolean previous)3904 _invite_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3905 {
3906     char* result = NULL;
3907 
3908     result = autocomplete_param_with_ac(input, "/invite", invite_ac, TRUE, previous);
3909     if (result) {
3910         return result;
3911     }
3912 
3913     jabber_conn_status_t conn_status = connection_get_status();
3914 
3915     if (conn_status == JABBER_CONNECTED) {
3916         result = autocomplete_param_with_func(input, "/invite send", roster_contact_autocomplete, previous, NULL);
3917         if (result) {
3918             return result;
3919         }
3920 
3921         result = autocomplete_param_with_func(input, "/invite decline", muc_invites_find, previous, NULL);
3922         if (result) {
3923             return result;
3924         }
3925     }
3926 
3927     return NULL;
3928 }
3929 
3930 static char*
_status_autocomplete(ProfWin * window,const char * const input,gboolean previous)3931 _status_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3932 {
3933     char* result = NULL;
3934 
3935     result = autocomplete_param_with_ac(input, "/status", status_ac, TRUE, previous);
3936     if (result) {
3937         return result;
3938     }
3939 
3940     jabber_conn_status_t conn_status = connection_get_status();
3941 
3942     if (conn_status == JABBER_CONNECTED) {
3943 
3944         // complete with: online, away etc.
3945         result = autocomplete_param_with_ac(input, "/status set", account_status_ac, TRUE, previous);
3946         if (result) {
3947             return result;
3948         }
3949 
3950         // Remove quote character before and after names when doing autocomplete
3951         char* unquoted = strip_arg_quotes(input);
3952 
3953         // MUC completion with nicknames
3954         if (window->type == WIN_MUC) {
3955             ProfMucWin* mucwin = (ProfMucWin*)window;
3956             assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
3957             Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
3958             if (nick_ac) {
3959                 result = autocomplete_param_with_ac(unquoted, "/status get", nick_ac, TRUE, previous);
3960                 if (result) {
3961                     free(unquoted);
3962                     return result;
3963                 }
3964             }
3965             // roster completion
3966         } else {
3967             result = autocomplete_param_with_func(unquoted, "/status get", roster_contact_autocomplete, previous, NULL);
3968             if (result) {
3969                 free(unquoted);
3970                 return result;
3971             }
3972         }
3973 
3974         free(unquoted);
3975     }
3976 
3977     return NULL;
3978 }
3979 
3980 static char*
_logging_autocomplete(ProfWin * window,const char * const input,gboolean previous)3981 _logging_autocomplete(ProfWin* window, const char* const input, gboolean previous)
3982 {
3983     char* result = NULL;
3984 
3985     result = autocomplete_param_with_ac(input, "/logging", logging_ac, TRUE, previous);
3986     if (result) {
3987         return result;
3988     }
3989 
3990     result = autocomplete_param_with_func(input, "/logging chat", prefs_autocomplete_boolean_choice, previous, NULL);
3991     if (result) {
3992         return result;
3993     }
3994 
3995     result = autocomplete_param_with_ac(input, "/logging group", logging_group_ac, TRUE, previous);
3996     return result;
3997 }
3998 
3999 static char*
_color_autocomplete(ProfWin * window,const char * const input,gboolean previous)4000 _color_autocomplete(ProfWin* window, const char* const input, gboolean previous)
4001 {
4002     char* result = NULL;
4003 
4004     result = autocomplete_param_with_func(input, "/color own", prefs_autocomplete_boolean_choice, previous, NULL);
4005     if (result) {
4006         return result;
4007     }
4008 
4009     result = autocomplete_param_with_ac(input, "/color", color_ac, TRUE, previous);
4010     return result;
4011 }
4012 
4013 static char*
_avatar_autocomplete(ProfWin * window,const char * const input,gboolean previous)4014 _avatar_autocomplete(ProfWin* window, const char* const input, gboolean previous)
4015 {
4016     char* result = NULL;
4017 
4018     result = autocomplete_param_with_ac(input, "/avatar", avatar_ac, TRUE, previous);
4019     if (result) {
4020         return result;
4021     }
4022 
4023     jabber_conn_status_t conn_status = connection_get_status();
4024     if (conn_status == JABBER_CONNECTED) {
4025         result = autocomplete_param_with_func(input, "/avatar get", roster_barejid_autocomplete, previous, NULL);
4026         if (result) {
4027             return result;
4028         }
4029 
4030         result = autocomplete_param_with_func(input, "/avatar open", roster_barejid_autocomplete, previous, NULL);
4031         if (result) {
4032             return result;
4033         }
4034     }
4035 
4036     return NULL;
4037 }
4038 
4039 static char*
_correction_autocomplete(ProfWin * window,const char * const input,gboolean previous)4040 _correction_autocomplete(ProfWin* window, const char* const input, gboolean previous)
4041 {
4042     char* result = NULL;
4043 
4044     result = autocomplete_param_with_ac(input, "/correction", correction_ac, TRUE, previous);
4045 
4046     return result;
4047 }
4048 
4049 static char*
_correct_autocomplete(ProfWin * window,const char * const input,gboolean previous)4050 _correct_autocomplete(ProfWin* window, const char* const input, gboolean previous)
4051 {
4052     char* last_message = NULL;
4053     switch (window->type) {
4054     case WIN_CHAT:
4055     {
4056         ProfChatWin* chatwin = (ProfChatWin*)window;
4057         assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
4058         last_message = chatwin->last_message;
4059         break;
4060     }
4061     case WIN_MUC:
4062     {
4063         ProfMucWin* mucwin = (ProfMucWin*)window;
4064         assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
4065         last_message = mucwin->last_message;
4066     }
4067     default:
4068         break;
4069     }
4070 
4071     if (last_message == NULL) {
4072         return NULL;
4073     }
4074 
4075     GString* result_str = g_string_new("/correct ");
4076     g_string_append(result_str, last_message);
4077     char* result = result_str->str;
4078     g_string_free(result_str, FALSE);
4079 
4080     return result;
4081 }
4082 
4083 static char*
_software_autocomplete(ProfWin * window,const char * const input,gboolean previous)4084 _software_autocomplete(ProfWin* window, const char* const input, gboolean previous)
4085 {
4086     char* result = NULL;
4087 
4088     if (window->type == WIN_CHAT) {
4089         ProfChatWin* chatwin = (ProfChatWin*)window;
4090         assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
4091 
4092         GString* search_str = g_string_new("/software ");
4093         g_string_append(search_str, chatwin->barejid);
4094         result = autocomplete_param_with_func(search_str->str, "/software", roster_fulljid_autocomplete, previous, NULL);
4095         g_string_free(search_str, TRUE);
4096     } else if (window->type == WIN_MUC) {
4097         ProfMucWin* mucwin = (ProfMucWin*)window;
4098         assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
4099 
4100         Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
4101 
4102         if (nick_ac) {
4103             result = autocomplete_param_with_ac(input, "/software", nick_ac, TRUE, previous);
4104             if (result) {
4105                 return result;
4106             }
4107         }
4108     } else {
4109         result = autocomplete_param_with_func(input, "/software", roster_fulljid_autocomplete, previous, NULL);
4110         if (result) {
4111             return result;
4112         }
4113     }
4114 
4115     return result;
4116 }
4117 
4118 static char*
_url_autocomplete(ProfWin * window,const char * const input,gboolean previous)4119 _url_autocomplete(ProfWin* window, const char* const input, gboolean previous)
4120 {
4121     char* result = NULL;
4122 
4123     result = autocomplete_param_with_ac(input, "/url", url_ac, TRUE, previous);
4124     if (result) {
4125         return result;
4126     }
4127 
4128     if (window->type == WIN_CHAT || window->type == WIN_MUC || window->type == WIN_PRIVATE) {
4129         result = autocomplete_param_with_func(input, "/url open", wins_get_url, previous, window);
4130         if (result) {
4131             return result;
4132         }
4133 
4134         result = autocomplete_param_with_func(input, "/url save", wins_get_url, previous, window);
4135     }
4136 
4137     return result;
4138 }
4139 
4140 static char*
_executable_autocomplete(ProfWin * window,const char * const input,gboolean previous)4141 _executable_autocomplete(ProfWin* window, const char* const input, gboolean previous)
4142 {
4143     char* result = NULL;
4144 
4145     result = autocomplete_param_with_ac(input, "/executable", executable_ac, TRUE, previous);
4146 
4147     return result;
4148 }
4149 
4150 static char*
_lastactivity_autocomplete(ProfWin * window,const char * const input,gboolean previous)4151 _lastactivity_autocomplete(ProfWin* window, const char* const input, gboolean previous)
4152 {
4153     char* result = NULL;
4154 
4155     result = autocomplete_param_with_ac(input, "/lastactivity", status_ac, TRUE, previous);
4156     if (!result) {
4157         return result;
4158     }
4159 
4160     jabber_conn_status_t conn_status = connection_get_status();
4161 
4162     if (conn_status == JABBER_CONNECTED) {
4163 
4164         result = autocomplete_param_with_func(input, "/lastactivity set", prefs_autocomplete_boolean_choice, previous, NULL);
4165         if (!result) {
4166             result = autocomplete_param_with_func(input, "/lastactivity get", roster_barejid_autocomplete, previous, NULL);
4167         }
4168     }
4169 
4170     return result;
4171 }
4172 
4173 static char*
_intype_autocomplete(ProfWin * window,const char * const input,gboolean previous)4174 _intype_autocomplete(ProfWin* window, const char* const input, gboolean previous)
4175 {
4176     char* result = NULL;
4177     result = autocomplete_param_with_func(input, "/intype console", prefs_autocomplete_boolean_choice, previous, NULL);
4178     if (result) {
4179         return result;
4180     }
4181 
4182     result = autocomplete_param_with_func(input, "/intype titlebar", prefs_autocomplete_boolean_choice, previous, NULL);
4183     if (result) {
4184         return result;
4185     }
4186 
4187     result = autocomplete_param_with_ac(input, "/intype", intype_ac, FALSE, previous);
4188     return result;
4189 }
4190