comparison mcabber/mcabber/commands.c @ 1668:41c26b7d2890

Install mcabber headers * Change mcabber headers naming scheme * Move 'src/' -> 'mcabber/' * Add missing include <mcabber/config.h>'s * Create and install clean config.h version in 'include/' * Move "dirty" config.h version to 'mcabber/' * Add $(top_srcdir) to compiler include path * Update modules HOWTO
author Myhailo Danylenko <isbear@ukrpost.net>
date Mon, 18 Jan 2010 15:36:19 +0200
parents mcabber/src/commands.c@64a7428afcb3
children c73b31124fa6
comparison
equal deleted inserted replaced
1667:8af0e0ad20ad 1668:41c26b7d2890
1 /*
2 * commands.c -- user commands handling
3 *
4 * Copyright (C) 2005-2009 Mikael Berthe <mikael@lilotux.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA
20 */
21
22 #include <string.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27
28 #include "commands.h"
29 #include "help.h"
30 #include "roster.h"
31 #include "screen.h"
32 #include "compl.h"
33 #include "hooks.h"
34 #include "hbuf.h"
35 #include "utils.h"
36 #include "settings.h"
37 #include "events.h"
38 #include "otr.h"
39 #include "utf8.h"
40 #include "xmpp.h"
41 #include "main.h"
42
43 #define IMSTATUS_AWAY "away"
44 #define IMSTATUS_ONLINE "online"
45 #define IMSTATUS_OFFLINE "offline"
46 #define IMSTATUS_FREE4CHAT "free"
47 #define IMSTATUS_INVISIBLE "invisible"
48 #define IMSTATUS_AVAILABLE "avail"
49 #define IMSTATUS_NOTAVAILABLE "notavail"
50 #define IMSTATUS_DONOTDISTURB "dnd"
51
52 // Return value container for the following functions
53 static int retval_for_cmds;
54
55 // Commands callbacks
56 static void do_roster(char *arg);
57 static void do_status(char *arg);
58 static void do_status_to(char *arg);
59 static void do_add(char *arg);
60 static void do_del(char *arg);
61 static void do_group(char *arg);
62 static void do_say(char *arg);
63 static void do_msay(char *arg);
64 static void do_say_to(char *arg);
65 static void do_buffer(char *arg);
66 static void do_clear(char *arg);
67 static void do_info(char *arg);
68 static void do_rename(char *arg);
69 static void do_move(char *arg);
70 static void do_set(char *arg);
71 static void do_alias(char *arg);
72 static void do_bind(char *arg);
73 static void do_connect(char *arg);
74 static void do_disconnect(char *arg);
75 static void do_rawxml(char *arg);
76 static void do_room(char *arg);
77 static void do_authorization(char *arg);
78 static void do_version(char *arg);
79 static void do_request(char *arg);
80 static void do_event(char *arg);
81 static void do_help(char *arg);
82 static void do_pgp(char *arg);
83 static void do_iline(char *arg);
84 static void do_screen_refresh(char *arg);
85 static void do_chat_disable(char *arg);
86 static void do_source(char *arg);
87 static void do_color(char *arg);
88 static void do_otr(char *arg);
89 static void do_otrpolicy(char *arg);
90 static void do_echo(char *arg);
91
92 static void do_say_internal(char *arg, int parse_flags);
93
94 // Global variable for the commands list
95 static GSList *Commands;
96
97 #ifdef MODULES_ENABLE
98 #include <gmodule.h>
99
100 static void do_load(char *arg);
101 static void do_unload(char *arg);
102
103 typedef struct {
104 char *name;
105 GModule *module;
106 } loaded_module_t;
107
108 GSList *loaded_modules = NULL;
109
110 gpointer cmd_del(const char *name)
111 {
112 GSList *sl_cmd;
113 for (sl_cmd = Commands; sl_cmd; sl_cmd = sl_cmd->next) {
114 cmd *command = (cmd *) sl_cmd->data;
115 if (!strcmp (command->name, name)) {
116 gpointer userdata = command->userdata;
117 Commands = g_slist_delete_link(Commands, sl_cmd);
118 compl_del_category_word(COMPL_CMD, command->name);
119 g_free(command);
120 return userdata;
121 }
122 }
123 return NULL;
124 }
125
126 // cmd_add()
127 // Adds a command to the commands list and to the CMD completion list
128 void cmd_add(const char *name, const char *help, guint flags_row1,
129 guint flags_row2, void (*f)(char*), gpointer userdata)
130 #define cmd_add(A, B, C, D, E) cmd_add (A, B, C, D, E, NULL);
131 #else
132 static void cmd_add(const char *name, const char *help,
133 guint flags_row1, guint flags_row2, void (*f)(char*))
134 #endif
135 {
136 cmd *n_cmd = g_new0(cmd, 1);
137 strncpy(n_cmd->name, name, 32-1);
138 n_cmd->help = help;
139 n_cmd->completion_flags[0] = flags_row1;
140 n_cmd->completion_flags[1] = flags_row2;
141 n_cmd->func = f;
142 #ifdef MODULES_ENABLE
143 n_cmd->userdata = userdata;
144 #endif
145 Commands = g_slist_prepend(Commands, n_cmd);
146 // Add to completion CMD category
147 compl_add_category_word(COMPL_CMD, name);
148 }
149
150 // cmd_init()
151 // Commands table initialization
152 // !!!
153 // After changing commands names and it arguments names here, you must change
154 // ones in init_bindings()!
155 //
156 void cmd_init(void)
157 {
158 cmd_add("add", "Add a jabber user", COMPL_JID, 0, &do_add);
159 cmd_add("alias", "Add an alias", 0, 0, &do_alias);
160 cmd_add("authorization", "Manage subscription authorizations",
161 COMPL_AUTH, COMPL_JID, &do_authorization);
162 cmd_add("bind", "Add an key binding", 0, 0, &do_bind);
163 cmd_add("buffer", "Manipulate current buddy's buffer (chat window)",
164 COMPL_BUFFER, 0, &do_buffer);
165 cmd_add("chat_disable", "Disable chat mode", 0, 0, &do_chat_disable);
166 cmd_add("clear", "Clear the dialog window", 0, 0, &do_clear);
167 cmd_add("color", "Set coloring options", COMPL_COLOR, 0, &do_color);
168 cmd_add("connect", "Connect to the server", 0, 0, &do_connect);
169 cmd_add("del", "Delete the current buddy", 0, 0, &do_del);
170 cmd_add("disconnect", "Disconnect from server", 0, 0, &do_disconnect);
171 cmd_add("echo", "Display a string in the log window", 0, 0, &do_echo);
172 cmd_add("event", "Process an event", COMPL_EVENTSID, COMPL_EVENTS, &do_event);
173 cmd_add("group", "Change group display settings",
174 COMPL_GROUP, COMPL_GROUPNAME, &do_group);
175 cmd_add("help", "Display some help", COMPL_CMD, 0, &do_help);
176 cmd_add("iline", "Manipulate input buffer", 0, 0, &do_iline);
177 cmd_add("info", "Show basic info on current buddy", 0, 0, &do_info);
178 cmd_add("move", "Move the current buddy to another group", COMPL_GROUPNAME,
179 0, &do_move);
180 cmd_add("msay", "Send a multi-lines message to the selected buddy",
181 COMPL_MULTILINE, 0, &do_msay);
182 cmd_add("otr", "Manage OTR settings", COMPL_OTR, COMPL_JID, &do_otr);
183 cmd_add("otrpolicy", "Manage OTR policies", COMPL_JID, COMPL_OTRPOLICY,
184 &do_otrpolicy);
185 cmd_add("pgp", "Manage PGP settings", COMPL_PGP, COMPL_JID, &do_pgp);
186 cmd_add("quit", "Exit the software", 0, 0, NULL);
187 cmd_add("rawxml", "Send a raw XML string", 0, 0, &do_rawxml);
188 cmd_add("rename", "Rename the current buddy", 0, 0, &do_rename);
189 cmd_add("request", "Send a Jabber IQ request", COMPL_REQUEST, COMPL_JID,
190 &do_request);
191 cmd_add("room", "MUC actions command", COMPL_ROOM, 0, &do_room);
192 cmd_add("roster", "Manipulate the roster/buddylist", COMPL_ROSTER, 0,
193 &do_roster);
194 cmd_add("say", "Say something to the selected buddy", 0, 0, &do_say);
195 cmd_add("say_to", "Say something to a specific buddy", COMPL_JID, 0,
196 &do_say_to);
197 cmd_add("screen_refresh", "Redraw mcabber screen", 0, 0, &do_screen_refresh);
198 //cmd_add("search");
199 cmd_add("set", "Set/query an option value", 0, 0, &do_set);
200 cmd_add("source", "Read a configuration file", 0, 0, &do_source);
201 cmd_add("status", "Show or set your status", COMPL_STATUS, 0, &do_status);
202 cmd_add("status_to", "Show or set your status for one recipient",
203 COMPL_JID, COMPL_STATUS, &do_status_to);
204 cmd_add("version", "Show mcabber version", 0, 0, &do_version);
205 #ifdef MODULES_ENABLE
206 cmd_add("load", "Load module", 0, 0, &do_load);
207 cmd_add("unload", "Unload module", 0, 0, &do_unload);
208 #endif
209
210 // Status category
211 compl_add_category_word(COMPL_STATUS, "online");
212 compl_add_category_word(COMPL_STATUS, "avail");
213 compl_add_category_word(COMPL_STATUS, "invisible");
214 compl_add_category_word(COMPL_STATUS, "free");
215 compl_add_category_word(COMPL_STATUS, "dnd");
216 compl_add_category_word(COMPL_STATUS, "notavail");
217 compl_add_category_word(COMPL_STATUS, "away");
218 compl_add_category_word(COMPL_STATUS, "offline");
219 compl_add_category_word(COMPL_STATUS, "message");
220
221 // Roster category
222 compl_add_category_word(COMPL_ROSTER, "bottom");
223 compl_add_category_word(COMPL_ROSTER, "top");
224 compl_add_category_word(COMPL_ROSTER, "up");
225 compl_add_category_word(COMPL_ROSTER, "down");
226 compl_add_category_word(COMPL_ROSTER, "group_prev");
227 compl_add_category_word(COMPL_ROSTER, "group_next");
228 compl_add_category_word(COMPL_ROSTER, "hide");
229 compl_add_category_word(COMPL_ROSTER, "show");
230 compl_add_category_word(COMPL_ROSTER, "toggle");
231 compl_add_category_word(COMPL_ROSTER, "display");
232 compl_add_category_word(COMPL_ROSTER, "hide_offline");
233 compl_add_category_word(COMPL_ROSTER, "show_offline");
234 compl_add_category_word(COMPL_ROSTER, "toggle_offline");
235 compl_add_category_word(COMPL_ROSTER, "item_lock");
236 compl_add_category_word(COMPL_ROSTER, "item_unlock");
237 compl_add_category_word(COMPL_ROSTER, "item_toggle_lock");
238 compl_add_category_word(COMPL_ROSTER, "alternate");
239 compl_add_category_word(COMPL_ROSTER, "search");
240 compl_add_category_word(COMPL_ROSTER, "unread_first");
241 compl_add_category_word(COMPL_ROSTER, "unread_next");
242 compl_add_category_word(COMPL_ROSTER, "note");
243
244 // Buffer category
245 compl_add_category_word(COMPL_BUFFER, "clear");
246 compl_add_category_word(COMPL_BUFFER, "bottom");
247 compl_add_category_word(COMPL_BUFFER, "top");
248 compl_add_category_word(COMPL_BUFFER, "up");
249 compl_add_category_word(COMPL_BUFFER, "down");
250 compl_add_category_word(COMPL_BUFFER, "search_backward");
251 compl_add_category_word(COMPL_BUFFER, "search_forward");
252 compl_add_category_word(COMPL_BUFFER, "date");
253 compl_add_category_word(COMPL_BUFFER, "%");
254 compl_add_category_word(COMPL_BUFFER, "purge");
255 compl_add_category_word(COMPL_BUFFER, "close");
256 compl_add_category_word(COMPL_BUFFER, "close_all");
257 compl_add_category_word(COMPL_BUFFER, "scroll_lock");
258 compl_add_category_word(COMPL_BUFFER, "scroll_unlock");
259 compl_add_category_word(COMPL_BUFFER, "scroll_toggle");
260 compl_add_category_word(COMPL_BUFFER, "list");
261 compl_add_category_word(COMPL_BUFFER, "save");
262
263 // Group category
264 compl_add_category_word(COMPL_GROUP, "fold");
265 compl_add_category_word(COMPL_GROUP, "unfold");
266 compl_add_category_word(COMPL_GROUP, "toggle");
267
268 // Multi-line (msay) category
269 compl_add_category_word(COMPL_MULTILINE, "abort");
270 compl_add_category_word(COMPL_MULTILINE, "begin");
271 compl_add_category_word(COMPL_MULTILINE, "send");
272 compl_add_category_word(COMPL_MULTILINE, "send_to");
273 compl_add_category_word(COMPL_MULTILINE, "toggle");
274 compl_add_category_word(COMPL_MULTILINE, "toggle_verbatim");
275 compl_add_category_word(COMPL_MULTILINE, "verbatim");
276
277 // Room category
278 compl_add_category_word(COMPL_ROOM, "affil");
279 compl_add_category_word(COMPL_ROOM, "ban");
280 compl_add_category_word(COMPL_ROOM, "bookmark");
281 compl_add_category_word(COMPL_ROOM, "destroy");
282 compl_add_category_word(COMPL_ROOM, "invite");
283 compl_add_category_word(COMPL_ROOM, "join");
284 compl_add_category_word(COMPL_ROOM, "kick");
285 compl_add_category_word(COMPL_ROOM, "leave");
286 compl_add_category_word(COMPL_ROOM, "names");
287 compl_add_category_word(COMPL_ROOM, "nick");
288 compl_add_category_word(COMPL_ROOM, "privmsg");
289 compl_add_category_word(COMPL_ROOM, "remove");
290 compl_add_category_word(COMPL_ROOM, "role");
291 compl_add_category_word(COMPL_ROOM, "setopt");
292 compl_add_category_word(COMPL_ROOM, "topic");
293 compl_add_category_word(COMPL_ROOM, "unban");
294 compl_add_category_word(COMPL_ROOM, "unlock");
295 compl_add_category_word(COMPL_ROOM, "whois");
296
297 // Authorization category
298 compl_add_category_word(COMPL_AUTH, "allow");
299 compl_add_category_word(COMPL_AUTH, "cancel");
300 compl_add_category_word(COMPL_AUTH, "request");
301 compl_add_category_word(COMPL_AUTH, "request_unsubscribe");
302
303 // Request (query) category
304 compl_add_category_word(COMPL_REQUEST, "last");
305 compl_add_category_word(COMPL_REQUEST, "time");
306 compl_add_category_word(COMPL_REQUEST, "vcard");
307 compl_add_category_word(COMPL_REQUEST, "version");
308
309 // Events category
310 compl_add_category_word(COMPL_EVENTS, "accept");
311 compl_add_category_word(COMPL_EVENTS, "ignore");
312 compl_add_category_word(COMPL_EVENTS, "reject");
313
314 // PGP category
315 compl_add_category_word(COMPL_PGP, "disable");
316 compl_add_category_word(COMPL_PGP, "enable");
317 compl_add_category_word(COMPL_PGP, "force");
318 compl_add_category_word(COMPL_PGP, "info");
319 compl_add_category_word(COMPL_PGP, "setkey");
320
321 // OTR category
322 compl_add_category_word(COMPL_OTR, "start");
323 compl_add_category_word(COMPL_OTR, "stop");
324 compl_add_category_word(COMPL_OTR, "fingerprint");
325 compl_add_category_word(COMPL_OTR, "smpq");
326 compl_add_category_word(COMPL_OTR, "smpr");
327 compl_add_category_word(COMPL_OTR, "smpa");
328 compl_add_category_word(COMPL_OTR, "info");
329 compl_add_category_word(COMPL_OTR, "key");
330
331 // OTR Policy category
332 compl_add_category_word(COMPL_OTRPOLICY, "plain");
333 compl_add_category_word(COMPL_OTRPOLICY, "manual");
334 compl_add_category_word(COMPL_OTRPOLICY, "opportunistic");
335 compl_add_category_word(COMPL_OTRPOLICY, "always");
336
337 // Color category
338 compl_add_category_word(COMPL_COLOR, "roster");
339 compl_add_category_word(COMPL_COLOR, "muc");
340 compl_add_category_word(COMPL_COLOR, "mucnick");
341 }
342
343 #ifdef MODULES_ENABLE
344 void cmd_deinit ()
345 {
346 GSList *el = loaded_modules;
347 while (el) {
348 loaded_module_t *module = el->data;
349 if (!g_module_close ((GModule *) module->module))
350 scr_LogPrint (LPRINT_LOGNORM, "* Module unloading failed: %s",
351 g_module_error ());
352 g_free (module->name);
353 g_free (module);
354 el = g_slist_next (el);
355 }
356 g_slist_free (loaded_modules);
357 }
358 #endif
359
360 // expandalias(line)
361 // If there is one, expand the alias in line and returns a new allocated line
362 // If no alias is found, returns line
363 // Note: if the returned pointer is different from line, the caller should
364 // g_free() the pointer after use
365 char *expandalias(const char *line)
366 {
367 const char *p1, *p2;
368 char *word;
369 const gchar *value;
370 char *newline = (char*)line;
371
372 // Ignore leading COMMAND_CHAR
373 for (p1 = line ; *p1 == COMMAND_CHAR ; p1++)
374 ;
375 // Locate the end of the word
376 for (p2 = p1 ; *p2 && (*p2 != ' ') ; p2++)
377 ;
378 // Extract the word and look for an alias in the list
379 word = g_strndup(p1, p2-p1);
380 value = settings_get(SETTINGS_TYPE_ALIAS, (const char*)word);
381 g_free(word);
382
383 if (value)
384 newline = g_strdup_printf("%c%s%s", COMMAND_CHAR, value, p2);
385
386 return newline;
387 }
388
389 // cmd_get
390 // Finds command in the command list structure.
391 // Returns a pointer to the cmd entry, or NULL if command not found.
392 cmd *cmd_get(const char *command)
393 {
394 const char *p1, *p2;
395 char *com;
396 GSList *sl_com;
397
398 // Ignore leading COMMAND_CHAR
399 for (p1 = command ; *p1 == COMMAND_CHAR ; p1++)
400 ;
401 // Locate the end of the command
402 for (p2 = p1 ; *p2 && (*p2 != ' ') ; p2++)
403 ;
404 // Copy the clean command
405 com = g_strndup(p1, p2-p1);
406
407 // Look for command in the list
408 for (sl_com=Commands; sl_com; sl_com = g_slist_next(sl_com)) {
409 if (!strcasecmp(com, ((cmd*)sl_com->data)->name))
410 break;
411 }
412 g_free(com);
413
414 if (sl_com) // Command has been found.
415 return (cmd*)sl_com->data;
416 return NULL;
417 }
418
419 // process_command(line, iscmd)
420 // Process a command line.
421 // If iscmd is TRUE, process the command even if verbatim mmode is set;
422 // it is intended to be used for key bindings.
423 // Return 255 if this is the /quit command, and 0 for the other commands.
424 int process_command(const char *line, guint iscmd)
425 {
426 char *p;
427 char *xpline;
428 cmd *curcmd;
429
430 if (!line)
431 return 0;
432
433 // We do alias expansion here
434 if (iscmd || scr_get_multimode() != 2)
435 xpline = expandalias(line);
436 else
437 xpline = (char*)line; // No expansion in verbatim multi-line mode
438
439 // We want to use a copy
440 if (xpline == line)
441 xpline = g_strdup(line);
442
443 // Remove trailing spaces:
444 for (p=xpline ; *p ; p++)
445 ;
446 for (p-- ; p>xpline && (*p == ' ') ; p--)
447 *p = 0;
448
449 // Command "quit"?
450 if ((iscmd || scr_get_multimode() != 2)
451 && (!strncasecmp(xpline, mkcmdstr("quit"), strlen(mkcmdstr("quit"))))) {
452 if (!xpline[5] || xpline[5] == ' ') {
453 g_free(xpline);
454 return 255;
455 }
456 } else if (iscmd && !strncasecmp(xpline, "quit", 4) &&
457 (!xpline[4] || xpline[4] == ' ')) {
458 // If iscmd is true we can have the command without the command prefix
459 // character (usually '/').
460 g_free(xpline);
461 return 255;
462 }
463
464 // If verbatim multi-line mode, we check if another /msay command is typed
465 if (!iscmd && scr_get_multimode() == 2
466 && (strncasecmp(xpline, mkcmdstr("msay "), strlen(mkcmdstr("msay "))))) {
467 // It isn't an /msay command
468 scr_append_multiline(xpline);
469 g_free(xpline);
470 return 0;
471 }
472
473 // Commands handling
474 curcmd = cmd_get(xpline);
475
476 if (!curcmd) {
477 scr_LogPrint(LPRINT_NORMAL, "Unrecognized command. "
478 "Please see the manual for a list of known commands.");
479 g_free(xpline);
480 return 0;
481 }
482 if (!curcmd->func) {
483 scr_LogPrint(LPRINT_NORMAL,
484 "This functionality is not yet implemented, sorry.");
485 g_free(xpline);
486 return 0;
487 }
488 // Lets go to the command parameters
489 for (p = xpline+1; *p && (*p != ' ') ; p++)
490 ;
491 // Skip spaces
492 while (*p && (*p == ' '))
493 p++;
494 // Call command-specific function
495 retval_for_cmds = 0;
496 #ifdef MODULES_ENABLE
497 if (curcmd->userdata)
498 (*(void (*)(char *p, gpointer u))curcmd->func)(p, curcmd->userdata);
499 else
500 (*curcmd->func)(p);
501 #else
502 (*curcmd->func)(p);
503 #endif
504 g_free(xpline);
505 return retval_for_cmds;
506 }
507
508 // process_line(line)
509 // Process a command/message line.
510 // If this isn't a command, this is a message and it is sent to the
511 // currently selected buddy.
512 // Return 255 if the line is the /quit command, or 0.
513 int process_line(const char *line)
514 {
515 if (!*line) { // User only pressed enter
516 if (scr_get_multimode()) {
517 scr_append_multiline("");
518 return 0;
519 }
520 if (current_buddy) {
521 if (buddy_gettype(BUDDATA(current_buddy)) & ROSTER_TYPE_GROUP)
522 do_group("toggle");
523 else {
524 // Enter chat mode
525 scr_set_chatmode(TRUE);
526 scr_ShowBuddyWindow();
527 }
528 }
529 return 0;
530 }
531
532 if (*line != COMMAND_CHAR) {
533 // This isn't a command
534 if (scr_get_multimode())
535 scr_append_multiline(line);
536 else
537 do_say_internal((char*)line, 0);
538 return 0;
539 }
540
541 /* It is _probably_ a command -- except for verbatim multi-line mode */
542 return process_command(line, FALSE);
543 }
544
545 // Helper routine for buffer item_{lock,unlock,toggle_lock}
546 // "lock" values: 1=lock 0=unlock -1=invert
547 static void roster_buddylock(char *bjid, int lock)
548 {
549 gpointer bud = NULL;
550 bool may_need_refresh = FALSE;
551
552 // Allow special jid "" or "." (current buddy)
553 if (bjid && (!*bjid || !strcmp(bjid, ".")))
554 bjid = NULL;
555
556 if (bjid) {
557 // The JID has been specified. Quick check...
558 if (check_jid_syntax(bjid)) {
559 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
560 "<%s> is not a valid Jabber ID.", bjid);
561 } else {
562 // Find the buddy
563 GSList *roster_elt;
564 roster_elt = roster_find(bjid, jidsearch,
565 ROSTER_TYPE_USER|ROSTER_TYPE_ROOM);
566 if (roster_elt)
567 bud = roster_elt->data;
568 else
569 scr_LogPrint(LPRINT_NORMAL, "This jid isn't in the roster.");
570 may_need_refresh = TRUE;
571 }
572 } else {
573 // Use the current buddy
574 if (current_buddy)
575 bud = BUDDATA(current_buddy);
576 }
577
578 // Update the ROSTER_FLAG_USRLOCK flag
579 if (bud) {
580 if (lock == -1)
581 lock = !(buddy_getflags(bud) & ROSTER_FLAG_USRLOCK);
582 buddy_setflags(bud, ROSTER_FLAG_USRLOCK, lock);
583 if (may_need_refresh) {
584 buddylist_build();
585 update_roster = TRUE;
586 }
587 }
588 }
589
590 // display_and_free_note(note, winId)
591 // Display the note information in the winId buffer, and free note
592 // (winId is a bare jid or NULL for the status window, in which case we
593 // display the note jid too)
594 static void display_and_free_note(struct annotation *note, const char *winId)
595 {
596 gchar tbuf[128];
597 GString *sbuf;
598 guint msg_flag = HBB_PREFIX_INFO;
599 /* We use the flag prefix_info for the first line, and prefix_cont
600 for the other lines, for better readability */
601
602 if (!note)
603 return;
604
605 sbuf = g_string_new("");
606
607 if (!winId) {
608 // We're writing to the status window, so let's show the jid too.
609 g_string_printf(sbuf, "Annotation on <%s>", note->jid);
610 scr_WriteIncomingMessage(winId, sbuf->str, 0, msg_flag, 0);
611 msg_flag = HBB_PREFIX_INFO | HBB_PREFIX_CONT;
612 }
613
614 // If we have the creation date, display it
615 if (note->cdate) {
616 strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S",
617 localtime(&note->cdate));
618 g_string_printf(sbuf, "Note created %s", tbuf);
619 scr_WriteIncomingMessage(winId, sbuf->str, 0, msg_flag, 0);
620 msg_flag = HBB_PREFIX_INFO | HBB_PREFIX_CONT;
621 }
622 // If we have the modification date, display it
623 // unless it's the same as the creation date
624 if (note->mdate && note->mdate != note->cdate) {
625 strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S",
626 localtime(&note->mdate));
627 g_string_printf(sbuf, "Note modified %s", tbuf);
628 scr_WriteIncomingMessage(winId, sbuf->str, 0, msg_flag, 0);
629 msg_flag = HBB_PREFIX_INFO | HBB_PREFIX_CONT;
630 }
631 // Note text
632 g_string_printf(sbuf, "Note: %s", note->text);
633 scr_WriteIncomingMessage(winId, sbuf->str, 0, msg_flag, 0);
634
635 g_string_free(sbuf, TRUE);
636 g_free(note->text);
637 g_free(note->jid);
638 g_free(note);
639 }
640
641 static void display_all_annotations(void)
642 {
643 GSList *notes;
644 notes = xmpp_get_all_storage_rosternotes();
645
646 if (!notes)
647 return;
648
649 // Call display_and_free_note() for each note,
650 // with winId = NULL (special window)
651 g_slist_foreach(notes, (GFunc)&display_and_free_note, NULL);
652 scr_setmsgflag_if_needed(SPECIAL_BUFFER_STATUS_ID, TRUE);
653 update_roster = TRUE;
654 g_slist_free(notes);
655 }
656
657 static void roster_note(char *arg)
658 {
659 const char *bjid;
660 guint type;
661
662 if (!current_buddy)
663 return;
664
665 bjid = buddy_getjid(BUDDATA(current_buddy));
666 type = buddy_gettype(BUDDATA(current_buddy));
667
668 if (!bjid && type == ROSTER_TYPE_SPECIAL && !arg) {
669 // We're in the status window (the only special buffer currently)
670 // Let's display all server notes
671 display_all_annotations();
672 return;
673 }
674
675 if (!bjid || (type != ROSTER_TYPE_USER &&
676 type != ROSTER_TYPE_ROOM &&
677 type != ROSTER_TYPE_AGENT)) {
678 scr_LogPrint(LPRINT_NORMAL, "This item can't have a note.");
679 return;
680 }
681
682 if (arg && *arg) { // Set a note
683 gchar *msg, *notetxt;
684 msg = to_utf8(arg);
685 if (!strcmp(msg, "-"))
686 notetxt = NULL; // delete note
687 else
688 notetxt = msg;
689 xmpp_set_storage_rosternotes(bjid, notetxt);
690 g_free(msg);
691 } else { // Display a note
692 struct annotation *note = xmpp_get_storage_rosternotes(bjid, FALSE);
693 if (note) {
694 display_and_free_note(note, bjid);
695 } else {
696 scr_WriteIncomingMessage(bjid, "This item doesn't have a note.", 0,
697 HBB_PREFIX_INFO, 0);
698 }
699 }
700 }
701
702 // roster_updown(updown, nitems)
703 // updown: -1=up, +1=down
704 inline static void roster_updown(int updown, char *nitems)
705 {
706 int nbitems;
707
708 if (!nitems || !*nitems)
709 nbitems = 1;
710 else
711 nbitems = strtol(nitems, NULL, 10);
712
713 if (nbitems > 0)
714 scr_RosterUpDown(updown, nbitems);
715 }
716
717 /* Commands callback functions */
718 /* All these do_*() functions will be called with a "arg" parameter */
719 /* (with arg not null) */
720
721 static void do_roster(char *arg)
722 {
723 char **paramlst;
724 char *subcmd;
725
726 paramlst = split_arg(arg, 2, 1); // subcmd, arg
727 subcmd = *paramlst;
728 arg = *(paramlst+1);
729
730 if (!subcmd || !*subcmd) {
731 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
732 free_arg_lst(paramlst);
733 return;
734 }
735
736 if (!strcasecmp(subcmd, "top")) {
737 scr_RosterTop();
738 update_roster = TRUE;
739 } else if (!strcasecmp(subcmd, "bottom")) {
740 scr_RosterBottom();
741 update_roster = TRUE;
742 } else if (!strcasecmp(subcmd, "hide")) {
743 scr_RosterVisibility(0);
744 } else if (!strcasecmp(subcmd, "show")) {
745 scr_RosterVisibility(1);
746 } else if (!strcasecmp(subcmd, "toggle")) {
747 scr_RosterVisibility(-1);
748 } else if (!strcasecmp(subcmd, "hide_offline")) {
749 buddylist_set_hide_offline_buddies(TRUE);
750 if (current_buddy)
751 buddylist_build();
752 update_roster = TRUE;
753 } else if (!strcasecmp(subcmd, "show_offline")) {
754 buddylist_set_hide_offline_buddies(FALSE);
755 buddylist_build();
756 update_roster = TRUE;
757 } else if (!strcasecmp(subcmd, "toggle_offline")) {
758 buddylist_set_hide_offline_buddies(-1);
759 buddylist_build();
760 update_roster = TRUE;
761 } else if (!strcasecmp(subcmd, "display")) {
762 scr_RosterDisplay(arg);
763 } else if (!strcasecmp(subcmd, "item_lock")) {
764 roster_buddylock(arg, 1);
765 } else if (!strcasecmp(subcmd, "item_unlock")) {
766 roster_buddylock(arg, 0);
767 } else if (!strcasecmp(subcmd, "item_toggle_lock")) {
768 roster_buddylock(arg, -1);
769 } else if (!strcasecmp(subcmd, "unread_first")) {
770 scr_RosterUnreadMessage(0);
771 } else if (!strcasecmp(subcmd, "unread_next")) {
772 scr_RosterUnreadMessage(1);
773 } else if (!strcasecmp(subcmd, "alternate")) {
774 scr_RosterJumpAlternate();
775 } else if (!strncasecmp(subcmd, "search", 6)) {
776 strip_arg_special_chars(arg);
777 if (!arg || !*arg) {
778 scr_LogPrint(LPRINT_NORMAL, "What name or JID are you looking for?");
779 free_arg_lst(paramlst);
780 return;
781 }
782 scr_RosterSearch(arg);
783 update_roster = TRUE;
784 } else if (!strcasecmp(subcmd, "up")) {
785 roster_updown(-1, arg);
786 } else if (!strcasecmp(subcmd, "down")) {
787 roster_updown(1, arg);
788 } else if (!strcasecmp(subcmd, "group_prev")) {
789 scr_RosterPrevGroup();
790 } else if (!strcasecmp(subcmd, "group_next")) {
791 scr_RosterNextGroup();
792 } else if (!strcasecmp(subcmd, "note")) {
793 roster_note(arg);
794 } else
795 scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
796 free_arg_lst(paramlst);
797 }
798
799 void do_color(char *arg)
800 {
801 char **paramlst;
802 char *subcmd;
803
804 paramlst = split_arg(arg, 2, 1); // subcmd, arg
805 subcmd = *paramlst;
806 arg = *(paramlst+1);
807
808 if (!subcmd || !*subcmd) {
809 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
810 free_arg_lst(paramlst);
811 return;
812 }
813
814 if (!strcasecmp(subcmd, "roster")) {
815 char *status, *wildcard, *color;
816 char **arglist = split_arg(arg, 3, 0);
817
818 status = *arglist;
819 wildcard = to_utf8(arglist[1]);
820 color = arglist[2];
821
822 if (status && !strcmp(status, "clear")) { // Not a color command, clear all
823 scr_RosterClearColor();
824 update_roster = TRUE;
825 } else {
826 if (!status || !*status || !wildcard || !*wildcard || !color || !*color) {
827 scr_LogPrint(LPRINT_NORMAL, "Missing argument");
828 } else {
829 update_roster = scr_RosterColor(status, wildcard, color)
830 || update_roster;
831 }
832 }
833 free_arg_lst(arglist);
834 g_free(wildcard);
835 } else if (!strcasecmp(subcmd, "muc")) {
836 char **arglist = split_arg(arg, 2, 0);
837 char *free_muc = to_utf8(*arglist);
838 const char *muc = free_muc, *mode = arglist[1];
839 if (!muc || !*muc)
840 scr_LogPrint(LPRINT_NORMAL, "What MUC?");
841 else {
842 if (!strcmp(muc, "."))
843 if (!(muc = CURRENT_JID))
844 scr_LogPrint(LPRINT_NORMAL, "No JID selected");
845 if (muc) {
846 if (check_jid_syntax(muc) && strcmp(muc, "*"))
847 scr_LogPrint(LPRINT_NORMAL, "Not a JID");
848 else {
849 if (!mode || !*mode || !strcasecmp(mode, "on"))
850 scr_MucColor(muc, MC_ALL);
851 else if (!strcasecmp(mode, "preset"))
852 scr_MucColor(muc, MC_PRESET);
853 else if (!strcasecmp(mode, "off"))
854 scr_MucColor(muc, MC_OFF);
855 else if (!strcmp(mode, "-"))
856 scr_MucColor(muc, MC_REMOVE);
857 else
858 scr_LogPrint(LPRINT_NORMAL, "Unknown coloring mode");
859 }
860 }
861 }
862 free_arg_lst(arglist);
863 g_free(free_muc);
864 } else if (!strcasecmp(subcmd, "mucnick")) {
865 char **arglist = split_arg(arg, 2, 0);
866 const char *nick = *arglist, *color = arglist[1];
867 if (!nick || !*nick || !color || !*color)
868 scr_LogPrint(LPRINT_NORMAL, "Missing argument");
869 else
870 scr_MucNickColor(nick, color);
871 free_arg_lst(arglist);
872 } else
873 scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
874 free_arg_lst(paramlst);
875 }
876
877 // cmd_setstatus(recipient, arg)
878 // Set your Jabber status.
879 // - if recipient is not NULL, the status is sent to this contact only
880 // - arg must be "status message" (message is optional)
881 void cmd_setstatus(const char *recipient, const char *arg)
882 {
883 char **paramlst;
884 char *status;
885 char *msg;
886 enum imstatus st;
887
888 if (!lm_connection_is_authenticated(lconnection)) {
889 scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
890 return;
891 }
892
893 // It makes sense to reset autoaway before changing the status
894 // (esp. for FIFO or remote commands) or the behaviour could be
895 // unexpected...
896 if (!recipient)
897 scr_CheckAutoAway(TRUE);
898
899 paramlst = split_arg(arg, 2, 1); // status, message
900 status = *paramlst;
901 msg = *(paramlst+1);
902
903 if (!status) {
904 free_arg_lst(paramlst);
905 return;
906 }
907
908 if (!strcasecmp(status, IMSTATUS_OFFLINE)) st = offline;
909 else if (!strcasecmp(status, IMSTATUS_ONLINE)) st = available;
910 else if (!strcasecmp(status, IMSTATUS_AVAILABLE)) st = available;
911 else if (!strcasecmp(status, IMSTATUS_AWAY)) st = away;
912 else if (!strcasecmp(status, IMSTATUS_INVISIBLE)) st = invisible;
913 else if (!strcasecmp(status, IMSTATUS_DONOTDISTURB)) st = dontdisturb;
914 else if (!strcasecmp(status, IMSTATUS_NOTAVAILABLE)) st = notavail;
915 else if (!strcasecmp(status, IMSTATUS_FREE4CHAT)) st = freeforchat;
916 else if (!strcasecmp(status, "message")) {
917 if (!msg || !*msg) {
918 // We want a message. If there's none, we give up.
919 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
920 free_arg_lst(paramlst);
921 return;
922 }
923 st = xmpp_getstatus(); // Preserve current status
924 } else {
925 scr_LogPrint(LPRINT_NORMAL, "Unrecognized status!");
926 free_arg_lst(paramlst);
927 return;
928 }
929
930 // Use provided message
931 if (msg && !*msg) {
932 msg = NULL;
933 }
934
935 // If a recipient is specified, let's don't use default status messages
936 if (recipient && !msg)
937 msg = "";
938
939 xmpp_setstatus(st, recipient, msg, FALSE);
940
941 free_arg_lst(paramlst);
942 }
943
944 static void do_status(char *arg)
945 {
946 if (!*arg) {
947 const char *sm = xmpp_getstatusmsg();
948 scr_LogPrint(LPRINT_NORMAL, "Your status is: [%c] %s",
949 imstatus2char[xmpp_getstatus()],
950 (sm ? sm : ""));
951 return;
952 }
953 arg = to_utf8(arg);
954 cmd_setstatus(NULL, arg);
955 g_free(arg);
956 }
957
958 static void do_status_to(char *arg)
959 {
960 char **paramlst;
961 char *fjid, *st, *msg;
962 char *jid_utf8 = NULL;
963
964 paramlst = split_arg(arg, 3, 1); // jid, status, [message]
965 fjid = *paramlst;
966 st = *(paramlst+1);
967 msg = *(paramlst+2);
968
969 if (!fjid || !st) {
970 scr_LogPrint(LPRINT_NORMAL,
971 "Please specify both a Jabber ID and a status.");
972 free_arg_lst(paramlst);
973 return;
974 }
975
976 // Allow things like /status_to "" away
977 if (!*fjid || !strcmp(fjid, "."))
978 fjid = NULL;
979
980 if (fjid) {
981 // The JID has been specified. Quick check...
982 if (check_jid_syntax(fjid)) {
983 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
984 "<%s> is not a valid Jabber ID.", fjid);
985 fjid = NULL;
986 } else {
987 // Convert jid to lowercase
988 char *p = fjid;
989 for ( ; *p && *p != JID_RESOURCE_SEPARATOR; p++)
990 *p = tolower(*p);
991 fjid = jid_utf8 = to_utf8(fjid);
992 }
993 } else {
994 // Add the current buddy
995 if (current_buddy)
996 fjid = (char*)buddy_getjid(BUDDATA(current_buddy));
997 if (!fjid)
998 scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
999 }
1000
1001 if (fjid) {
1002 char *cmdline;
1003 if (!msg)
1004 msg = "";
1005 msg = to_utf8(msg);
1006 cmdline = g_strdup_printf("%s %s", st, msg);
1007 scr_LogPrint(LPRINT_LOGNORM, "Sending to <%s> /status %s", fjid, cmdline);
1008 cmd_setstatus(fjid, cmdline);
1009 g_free(msg);
1010 g_free(cmdline);
1011 g_free(jid_utf8);
1012 }
1013 free_arg_lst(paramlst);
1014 }
1015
1016 static void do_add(char *arg)
1017 {
1018 char **paramlst;
1019 char *id, *nick;
1020 char *jid_utf8 = NULL;
1021
1022 if (!lm_connection_is_authenticated(lconnection)) {
1023 scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
1024 return;
1025 }
1026
1027 paramlst = split_arg(arg, 2, 0); // jid, [nickname]
1028 id = *paramlst;
1029 nick = *(paramlst+1);
1030
1031 if (!id)
1032 nick = NULL; // Allow things like: /add "" nick
1033 else if (!*id || !strcmp(id, "."))
1034 id = NULL;
1035
1036 if (id) {
1037 // The JID has been specified. Quick check...
1038 if (check_jid_syntax(id)) {
1039 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
1040 "<%s> is not a valid Jabber ID.", id);
1041 id = NULL;
1042 } else {
1043 mc_strtolower(id);
1044 // Actually an UTF-8 id isn't needed because only the bare jid will
1045 // be used.
1046 id = jid_utf8 = to_utf8(id);
1047 }
1048 } else {
1049 // Add the current buddy
1050 if (current_buddy)
1051 id = (char*)buddy_getjid(BUDDATA(current_buddy));
1052 if (!id)
1053 scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
1054 }
1055
1056 if (nick)
1057 nick = to_utf8(nick);
1058
1059 if (id) {
1060 // 2nd parameter = optional nickname
1061 xmpp_addbuddy(id, nick, NULL);
1062 scr_LogPrint(LPRINT_LOGNORM, "Sent presence notification request to <%s>.",
1063 id);
1064 }
1065
1066 g_free(jid_utf8);
1067 g_free(nick);
1068 free_arg_lst(paramlst);
1069 }
1070
1071 static void do_del(char *arg)
1072 {
1073 const char *bjid;
1074
1075 if (*arg) {
1076 scr_LogPrint(LPRINT_NORMAL, "This action does not require a parameter; "
1077 "the currently-selected buddy will be deleted.");
1078 return;
1079 }
1080
1081 if (!current_buddy)
1082 return;
1083 bjid = buddy_getjid(BUDDATA(current_buddy));
1084 if (!bjid)
1085 return;
1086
1087 if (buddy_gettype(BUDDATA(current_buddy)) & ROSTER_TYPE_ROOM) {
1088 // This is a chatroom
1089 if (buddy_getinsideroom(BUDDATA(current_buddy))) {
1090 scr_LogPrint(LPRINT_NORMAL, "You haven't left this room!");
1091 return;
1092 }
1093 }
1094
1095 // Close the buffer
1096 scr_BufferPurge(1, NULL);
1097
1098 scr_LogPrint(LPRINT_LOGNORM, "Removing <%s>...", bjid);
1099 xmpp_delbuddy(bjid);
1100 scr_UpdateBuddyWindow();
1101 }
1102
1103 static void do_group(char *arg)
1104 {
1105 gpointer group = NULL;
1106 guint leave_buddywindow;
1107 char **paramlst;
1108 char *subcmd;
1109 enum { group_toggle = -1, group_unfold = 0, group_fold = 1 } group_state = 0;
1110
1111 if (!*arg) {
1112 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
1113 return;
1114 }
1115
1116 if (!current_buddy)
1117 return;
1118
1119 paramlst = split_arg(arg, 2, 0); // subcmd, [arg]
1120 subcmd = *paramlst;
1121 arg = *(paramlst+1);
1122
1123 if (!subcmd || !*subcmd)
1124 goto do_group_return; // Should not happen anyway
1125
1126 if (arg && *arg) {
1127 GSList *roster_elt;
1128 char *group_utf8 = to_utf8(arg);
1129 roster_elt = roster_find(group_utf8, namesearch, ROSTER_TYPE_GROUP);
1130 g_free(group_utf8);
1131 if (roster_elt)
1132 group = buddy_getgroup(roster_elt->data);
1133 } else {
1134 group = buddy_getgroup(BUDDATA(current_buddy));
1135 }
1136 if (!group)
1137 goto do_group_return;
1138
1139 // We'll have to redraw the chat window if we're not currently on the group
1140 // entry itself, because it means we'll have to leave the current buddy
1141 // chat window.
1142 leave_buddywindow = (group != BUDDATA(current_buddy) &&
1143 group == buddy_getgroup(BUDDATA(current_buddy)));
1144
1145
1146 if (!(buddy_gettype(group) & ROSTER_TYPE_GROUP)) {
1147 scr_LogPrint(LPRINT_NORMAL, "You need to select a group.");
1148 goto do_group_return;
1149 }
1150
1151 if (!strcasecmp(subcmd, "expand") || !strcasecmp(subcmd, "unfold"))
1152 group_state = group_unfold;
1153 else if (!strcasecmp(subcmd, "shrink") || !strcasecmp(subcmd, "fold"))
1154 group_state = group_fold;
1155 else if (!strcasecmp(subcmd, "toggle"))
1156 group_state = group_toggle;
1157 else {
1158 scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
1159 goto do_group_return;
1160 }
1161
1162 if (group_state != group_unfold && leave_buddywindow)
1163 scr_RosterPrevGroup();
1164
1165 buddy_hide_group(group, group_state);
1166
1167 buddylist_build();
1168 update_roster = TRUE;
1169
1170 do_group_return:
1171 free_arg_lst(paramlst);
1172 }
1173
1174 static int send_message_to(const char *fjid, const char *msg, const char *subj,
1175 LmMessageSubType type_overwrite, bool quiet)
1176 {
1177 char *bare_jid, *rp;
1178 char *hmsg;
1179 gint crypted;
1180 gint retval = 0;
1181 int isroom;
1182 gpointer xep184 = NULL;
1183
1184 if (!lm_connection_is_authenticated(lconnection)) {
1185 scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
1186 return 1;
1187 }
1188 if (!fjid || !*fjid) {
1189 scr_LogPrint(LPRINT_NORMAL, "You must specify a Jabber ID.");
1190 return 1;
1191 }
1192 if (!msg || !*msg) {
1193 scr_LogPrint(LPRINT_NORMAL, "You must specify a message.");
1194 return 1;
1195 }
1196 if (check_jid_syntax((char*)fjid)) {
1197 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
1198 "<%s> is not a valid Jabber ID.", fjid);
1199 return 1;
1200 }
1201
1202 // We must use the bare jid in hk_message_out()
1203 rp = strchr(fjid, JID_RESOURCE_SEPARATOR);
1204 if (rp)
1205 bare_jid = g_strndup(fjid, rp - fjid);
1206 else
1207 bare_jid = (char*)fjid;
1208
1209 if (!quiet) {
1210 // Jump to window, create one if needed
1211 scr_RosterJumpJid(bare_jid);
1212 }
1213
1214 // Check if we're sending a message to a conference room
1215 // If not, we must make sure rp is NULL, for hk_message_out()
1216 isroom = !!roster_find(bare_jid, jidsearch, ROSTER_TYPE_ROOM);
1217 if (rp) {
1218 if (isroom) rp++;
1219 else rp = NULL;
1220 }
1221 isroom = isroom && (!rp || !*rp);
1222
1223 // local part (UI, logging, etc.)
1224 if (subj)
1225 hmsg = g_strdup_printf("[%s]\n%s", subj, msg);
1226 else
1227 hmsg = (char*)msg;
1228
1229 // Network part
1230 xmpp_send_msg(fjid, msg, (isroom ? ROSTER_TYPE_ROOM : ROSTER_TYPE_USER),
1231 subj, FALSE, &crypted, type_overwrite, &xep184);
1232
1233 if (crypted == -1) {
1234 scr_LogPrint(LPRINT_LOGNORM, "Encryption error. Message was not sent.");
1235 retval = 1;
1236 goto send_message_to_return;
1237 }
1238
1239 // Hook
1240 if (!isroom)
1241 hk_message_out(bare_jid, rp, 0, hmsg, crypted, xep184);
1242
1243 send_message_to_return:
1244 if (hmsg != msg) g_free(hmsg);
1245 if (rp) g_free(bare_jid);
1246 return retval;
1247 }
1248
1249 // send_message(msg, subj, type_overwrite)
1250 // Write the message in the buddy's window and send the message on
1251 // the network.
1252 static void send_message(const char *msg, const char *subj,
1253 LmMessageSubType type_overwrite)
1254 {
1255 const char *bjid;
1256
1257 if (!current_buddy) {
1258 scr_LogPrint(LPRINT_NORMAL, "No buddy is currently selected.");
1259 return;
1260 }
1261
1262 bjid = CURRENT_JID;
1263 if (!bjid) {
1264 scr_LogPrint(LPRINT_NORMAL, "No buddy is currently selected.");
1265 return;
1266 }
1267
1268 send_message_to(bjid, msg, subj, type_overwrite, FALSE);
1269 }
1270
1271 static LmMessageSubType scan_mtype(char **arg)
1272 {
1273 //Try splitting it
1274 char **parlist = split_arg(*arg, 2, 1);
1275 LmMessageSubType result = LM_MESSAGE_SUB_TYPE_NOT_SET;
1276 //Is it any good parameter?
1277 if (parlist && *parlist) {
1278 if (!strcmp("-n", *parlist)) {
1279 result = LM_MESSAGE_SUB_TYPE_NORMAL;
1280 } else if (!strcmp("-h", *parlist)) {
1281 result = LM_MESSAGE_SUB_TYPE_HEADLINE;
1282 }
1283 if (result != LM_MESSAGE_SUB_TYPE_NOT_SET || (!strcmp("--", *parlist)))
1284 *arg += strlen(*arg) - (parlist[1] ? strlen(parlist[1]) : 0);
1285 }
1286 //Anything found? -> skip it
1287 free_arg_lst(parlist);
1288 return result;
1289 }
1290
1291 static void do_say_internal(char *arg, int parse_flags)
1292 {
1293 gpointer bud;
1294 LmMessageSubType msgtype = LM_MESSAGE_SUB_TYPE_NOT_SET;
1295
1296 scr_set_chatmode(TRUE);
1297 scr_ShowBuddyWindow();
1298
1299 if (!current_buddy) {
1300 scr_LogPrint(LPRINT_NORMAL,
1301 "Whom are you talking to? Please select a buddy.");
1302 return;
1303 }
1304
1305 bud = BUDDATA(current_buddy);
1306 if (!(buddy_gettype(bud) &
1307 (ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_ROOM))) {
1308 scr_LogPrint(LPRINT_NORMAL, "This is not a user.");
1309 return;
1310 }
1311
1312 buddy_setflags(bud, ROSTER_FLAG_LOCK, TRUE);
1313 if (parse_flags)
1314 msgtype = scan_mtype(&arg);
1315 arg = to_utf8(arg);
1316 send_message(arg, NULL, msgtype);
1317 g_free(arg);
1318 }
1319
1320 static void do_say(char *arg) {
1321 do_say_internal(arg, 1);
1322 }
1323
1324 static void do_msay(char *arg)
1325 {
1326 /* Parameters: begin verbatim abort send send_to */
1327 char **paramlst;
1328 char *subcmd;
1329
1330 paramlst = split_arg(arg, 2, 1); // subcmd, arg
1331 subcmd = *paramlst;
1332 arg = *(paramlst+1);
1333
1334 if (!subcmd || !*subcmd) {
1335 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
1336 scr_LogPrint(LPRINT_NORMAL, "Please read the manual before using "
1337 "the /msay command.");
1338 scr_LogPrint(LPRINT_NORMAL, "(Use \"%s begin\" to enter "
1339 "multi-line mode...)", mkcmdstr("msay"));
1340 goto do_msay_return;
1341 }
1342
1343 if (!strcasecmp(subcmd, "toggle")) {
1344 if (scr_get_multimode())
1345 subcmd = "send";
1346 else
1347 subcmd = "begin";
1348 } else if (!strcasecmp(subcmd, "toggle_verbatim")) {
1349 if (scr_get_multimode())
1350 subcmd = "send";
1351 else
1352 subcmd = "verbatim";
1353 }
1354
1355 if (!strcasecmp(subcmd, "abort")) {
1356 if (scr_get_multimode())
1357 scr_LogPrint(LPRINT_NORMAL, "Leaving multi-line message mode.");
1358 scr_set_multimode(FALSE, NULL);
1359 goto do_msay_return;
1360 } else if ((!strcasecmp(subcmd, "begin")) ||
1361 (!strcasecmp(subcmd, "verbatim"))) {
1362 bool verbat;
1363 gchar *subj_utf8 = to_utf8(arg);
1364 if (!strcasecmp(subcmd, "verbatim")) {
1365 scr_set_multimode(2, subj_utf8);
1366 verbat = TRUE;
1367 } else {
1368 scr_set_multimode(1, subj_utf8);
1369 verbat = FALSE;
1370 }
1371
1372 scr_LogPrint(LPRINT_NORMAL, "Entered %smulti-line message mode.",
1373 verbat ? "VERBATIM " : "");
1374 scr_LogPrint(LPRINT_NORMAL, "Select a buddy and use \"%s send\" "
1375 "when your message is ready.", mkcmdstr("msay"));
1376 if (verbat)
1377 scr_LogPrint(LPRINT_NORMAL, "Use \"%s abort\" to abort this mode.",
1378 mkcmdstr("msay"));
1379 g_free(subj_utf8);
1380 goto do_msay_return;
1381 } else if (strcasecmp(subcmd, "send") && strcasecmp(subcmd, "send_to")) {
1382 scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
1383 goto do_msay_return;
1384 }
1385
1386 /* send/send_to command */
1387
1388 if (!scr_get_multimode()) {
1389 scr_LogPrint(LPRINT_NORMAL, "No message to send. "
1390 "Use \"%s begin\" first.", mkcmdstr("msay"));
1391 goto do_msay_return;
1392 }
1393
1394 scr_set_chatmode(TRUE);
1395 scr_ShowBuddyWindow();
1396
1397 if (!strcasecmp(subcmd, "send_to")) {
1398 int err = FALSE;
1399 gchar *msg_utf8;
1400 LmMessageSubType msg_type = scan_mtype(&arg);
1401 // Let's send to the specified JID. We leave now if there
1402 // has been an error (so we don't leave multi-line mode).
1403 arg = to_utf8(arg);
1404 msg_utf8 = to_utf8(scr_get_multiline());
1405 if (msg_utf8) {
1406 err = send_message_to(arg, msg_utf8, scr_get_multimode_subj(), msg_type,
1407 FALSE);
1408 g_free(msg_utf8);
1409 }
1410 g_free(arg);
1411 if (err)
1412 goto do_msay_return;
1413 } else { // Send to currently selected buddy
1414 gpointer bud;
1415 gchar *msg_utf8;
1416
1417 if (!current_buddy) {
1418 scr_LogPrint(LPRINT_NORMAL, "Whom are you talking to?");
1419 goto do_msay_return;
1420 }
1421
1422 bud = BUDDATA(current_buddy);
1423 if (!(buddy_gettype(bud) &
1424 (ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_ROOM))) {
1425 scr_LogPrint(LPRINT_NORMAL, "This is not a user.");
1426 goto do_msay_return;
1427 }
1428
1429 buddy_setflags(bud, ROSTER_FLAG_LOCK, TRUE);
1430 msg_utf8 = to_utf8(scr_get_multiline());
1431 if (msg_utf8) {
1432 send_message(msg_utf8, scr_get_multimode_subj(), scan_mtype(&arg));
1433 g_free(msg_utf8);
1434 }
1435 }
1436 scr_set_multimode(FALSE, NULL);
1437 scr_LogPrint(LPRINT_NORMAL, "You have left multi-line message mode.");
1438 do_msay_return:
1439 free_arg_lst(paramlst);
1440 }
1441
1442 // load_message_from_file(filename)
1443 // Read the whole content of a file.
1444 // The data are converted to UTF8, they should be freed by the caller after
1445 // use.
1446 char *load_message_from_file(const char *filename)
1447 {
1448 FILE *fd;
1449 struct stat buf;
1450 char *msgbuf, *msgbuf_utf8;
1451 char *p;
1452 char *next_utf8_char;
1453 size_t len;
1454
1455 fd = fopen(filename, "r");
1456
1457 if (!fd || fstat(fileno(fd), &buf)) {
1458 scr_LogPrint(LPRINT_LOGNORM, "Cannot open message file (%s)", filename);
1459 return NULL;
1460 }
1461 if (!buf.st_size || buf.st_size >= HBB_BLOCKSIZE) {
1462 if (!buf.st_size)
1463 scr_LogPrint(LPRINT_LOGNORM, "Message file is empty (%s)", filename);
1464 else
1465 scr_LogPrint(LPRINT_LOGNORM, "Message file is too big (%s)", filename);
1466 fclose(fd);
1467 return NULL;
1468 }
1469
1470 msgbuf = g_new0(char, HBB_BLOCKSIZE);
1471 len = fread(msgbuf, 1, HBB_BLOCKSIZE-1, fd);
1472 fclose(fd);
1473
1474 next_utf8_char = msgbuf;
1475
1476 // Check there is no binary data. It must be a *message* file!
1477 for (p = msgbuf ; *p ; p++) {
1478 if (utf8_mode) {
1479 if (p == next_utf8_char) {
1480 if (!iswprint(get_char(p)) && *p != '\n' && *p != '\t')
1481 break;
1482 next_utf8_char = next_char(p);
1483 }
1484 } else {
1485 unsigned char sc = *p;
1486 if (!iswprint(sc) && sc != '\n' && sc != '\t')
1487 break;
1488 }
1489 }
1490
1491 if (*p || (size_t)(p-msgbuf) != len) { // We're not at the End Of Line...
1492 scr_LogPrint(LPRINT_LOGNORM, "Message file contains "
1493 "invalid characters (%s)", filename);
1494 g_free(msgbuf);
1495 return NULL;
1496 }
1497
1498 // p is now at the EOL
1499 // Let's strip trailing newlines
1500 if (p > msgbuf)
1501 p--;
1502 while (p > msgbuf && *p == '\n')
1503 *p-- = 0;
1504
1505 // It could be empty, once the trailing newlines are gone
1506 if (p == msgbuf && *p == '\n') {
1507 scr_LogPrint(LPRINT_LOGNORM, "Message file is empty (%s)", filename);
1508 g_free(msgbuf);
1509 return NULL;
1510 }
1511
1512 msgbuf_utf8 = to_utf8(msgbuf);
1513
1514 if (!msgbuf_utf8 && msgbuf)
1515 scr_LogPrint(LPRINT_LOGNORM, "Message file charset conversion error (%s)",
1516 filename);
1517 g_free(msgbuf);
1518 return msgbuf_utf8;
1519 }
1520
1521 static void do_say_to(char *arg)
1522 {
1523 char **paramlst;
1524 char *fjid, *msg;
1525 char *file = NULL;
1526 LmMessageSubType msg_type = LM_MESSAGE_SUB_TYPE_NOT_SET;
1527 bool quiet = FALSE;
1528
1529 if (!lm_connection_is_authenticated(lconnection)) {
1530 scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
1531 return;
1532 }
1533
1534 msg_type = scan_mtype(&arg);
1535 paramlst = split_arg(arg, 2, 1); // jid, message (or option, jid, message)
1536
1537 if (!*paramlst) { // No parameter?
1538 scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
1539 free_arg_lst(paramlst);
1540 return;
1541 }
1542
1543 // Check for an option parameter
1544 while (*paramlst) {
1545 if (!strcmp(*paramlst, "-q")) {
1546 char **oldparamlst = paramlst;
1547 paramlst = split_arg(*(oldparamlst+1), 2, 1); // jid, message
1548 free_arg_lst(oldparamlst);
1549 quiet = TRUE;
1550 } else if (!strcmp(*paramlst, "-f")) {
1551 char **oldparamlst = paramlst;
1552 paramlst = split_arg(*(oldparamlst+1), 2, 1); // filename, jid
1553 free_arg_lst(oldparamlst);
1554 if (!*paramlst) {
1555 scr_LogPrint(LPRINT_NORMAL, "Wrong usage.");
1556 return;
1557 }
1558 file = g_strdup(*paramlst);
1559 // One more parameter shift...
1560 oldparamlst = paramlst;
1561 paramlst = split_arg(*(oldparamlst+1), 2, 1); // jid, nothing
1562 free_arg_lst(oldparamlst);
1563 } else
1564 break;
1565 }
1566
1567 if (!*paramlst) {
1568 scr_LogPrint(LPRINT_NORMAL, "Wrong usage.");
1569 return;
1570 }
1571
1572 fjid = *paramlst;
1573 msg = *(paramlst+1);
1574
1575 if (!strcmp(fjid, ".")) {
1576 // Send the message to the current buddy
1577 if (current_buddy)
1578 fjid = (char*)buddy_getjid(BUDDATA(current_buddy));
1579 if (!fjid) {
1580 scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
1581 free_arg_lst(paramlst);
1582 return;
1583 }
1584 } else if (check_jid_syntax(fjid)) {
1585 scr_LogPrint(LPRINT_NORMAL, "Please specify a valid Jabber ID.");
1586 free_arg_lst(paramlst);
1587 return;
1588 }
1589
1590 fjid = to_utf8(fjid);
1591 if (!file) {
1592 msg = to_utf8(msg);
1593 } else {
1594 char *filename_xp;
1595 if (msg)
1596 scr_LogPrint(LPRINT_NORMAL, "say_to: extra parameter ignored.");
1597 filename_xp = expand_filename(file);
1598 msg = load_message_from_file(filename_xp);
1599 g_free(filename_xp);
1600 g_free(file);
1601 }
1602
1603 send_message_to(fjid, msg, NULL, msg_type, quiet);
1604
1605 g_free(fjid);
1606 g_free(msg);
1607 free_arg_lst(paramlst);
1608 }
1609
1610 // buffer_updown(updown, nblines)
1611 // updown: -1=up, +1=down
1612 inline static void buffer_updown(int updown, char *nlines)
1613 {
1614 int nblines;
1615
1616 if (!nlines || !*nlines)
1617 nblines = 0;
1618 else
1619 nblines = strtol(nlines, NULL, 10);
1620
1621 if (nblines >= 0)
1622 scr_BufferScrollUpDown(updown, nblines);
1623 }
1624
1625 static void buffer_search(int direction, char *arg)
1626 {
1627 if (!arg || !*arg) {
1628 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
1629 return;
1630 }
1631
1632 scr_BufferSearch(direction, arg);
1633 }
1634
1635 static void buffer_date(char *date)
1636 {
1637 time_t t;
1638
1639 if (!date || !*date) {
1640 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
1641 return;
1642 }
1643
1644 strip_arg_special_chars(date);
1645
1646 t = from_iso8601(date, 0);
1647 if (t)
1648 scr_BufferDate(t);
1649 else
1650 scr_LogPrint(LPRINT_NORMAL, "The date you specified is "
1651 "not correctly formatted or invalid.");
1652 }
1653
1654 static void buffer_percent(char *arg1, char *arg2)
1655 {
1656 // Basically, user has typed "%arg1 arg2"
1657 // "%50" -> arg1 = 50, arg2 null pointer
1658 // "% 50" -> arg1 = \0, arg2 = 50
1659
1660 if (!*arg1 && (!arg2 || !*arg2)) { // No value
1661 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
1662 return;
1663 }
1664
1665 if (*arg1 && arg2 && *arg2) { // Two values
1666 scr_LogPrint(LPRINT_NORMAL, "Wrong parameters.");
1667 return;
1668 }
1669
1670 scr_BufferPercent(atoi((*arg1 ? arg1 : arg2)));
1671 }
1672
1673 static void do_buffer(char *arg)
1674 {
1675 char **paramlst;
1676 char *subcmd;
1677
1678 if (!current_buddy)
1679 return;
1680
1681 paramlst = split_arg(arg, 2, 1); // subcmd, arg
1682 subcmd = *paramlst;
1683 arg = *(paramlst+1);
1684
1685 if (!subcmd || !*subcmd) {
1686 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
1687 free_arg_lst(paramlst);
1688 return;
1689 }
1690
1691 if (buddy_gettype(BUDDATA(current_buddy)) & ROSTER_TYPE_GROUP &&
1692 strcasecmp(subcmd, "close_all")) {
1693 scr_LogPrint(LPRINT_NORMAL, "Groups have no buffer.");
1694 free_arg_lst(paramlst);
1695 return;
1696 }
1697
1698 if (!strcasecmp(subcmd, "top")) {
1699 scr_BufferTopBottom(-1);
1700 } else if (!strcasecmp(subcmd, "bottom")) {
1701 scr_BufferTopBottom(1);
1702 } else if (!strcasecmp(subcmd, "clear")) {
1703 scr_BufferClear();
1704 } else if (!strcasecmp(subcmd, "close")) {
1705 scr_BufferPurge(1, arg);
1706 } else if (!strcasecmp(subcmd, "close_all")) {
1707 scr_BufferPurgeAll(1);
1708 } else if (!strcasecmp(subcmd, "purge")) {
1709 scr_BufferPurge(0, arg);
1710 } else if (!strcasecmp(subcmd, "scroll_lock")) {
1711 scr_BufferScrollLock(1);
1712 } else if (!strcasecmp(subcmd, "scroll_unlock")) {
1713 scr_BufferScrollLock(0);
1714 } else if (!strcasecmp(subcmd, "scroll_toggle")) {
1715 scr_BufferScrollLock(-1);
1716 } else if (!strcasecmp(subcmd, "up")) {
1717 buffer_updown(-1, arg);
1718 } else if (!strcasecmp(subcmd, "down")) {
1719 buffer_updown(1, arg);
1720 } else if (!strcasecmp(subcmd, "search_backward")) {
1721 strip_arg_special_chars(arg);
1722 buffer_search(-1, arg);
1723 } else if (!strcasecmp(subcmd, "search_forward")) {
1724 strip_arg_special_chars(arg);
1725 buffer_search(1, arg);
1726 } else if (!strcasecmp(subcmd, "date")) {
1727 buffer_date(arg);
1728 } else if (*subcmd == '%') {
1729 buffer_percent(subcmd+1, arg);
1730 } else if (!strcasecmp(subcmd, "save")) {
1731 scr_BufferDump(arg);
1732 } else if (!strcasecmp(subcmd, "list")) {
1733 scr_BufferList();
1734 } else {
1735 scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
1736 }
1737
1738 free_arg_lst(paramlst);
1739 }
1740
1741 static void do_clear(char *arg) // Alias for "buffer clear"
1742 {
1743 do_buffer("clear");
1744 }
1745
1746 static void do_info(char *arg)
1747 {
1748 gpointer bud;
1749 const char *bjid, *name;
1750 guint type, on_srv;
1751 char *buffer;
1752 enum subscr esub;
1753
1754 if (!current_buddy)
1755 return;
1756 bud = BUDDATA(current_buddy);
1757
1758 bjid = buddy_getjid(bud);
1759 name = buddy_getname(bud);
1760 type = buddy_gettype(bud);
1761 esub = buddy_getsubscription(bud);
1762 on_srv = buddy_getonserverflag(bud);
1763
1764 buffer = g_new(char, 4096);
1765
1766 if (bjid) {
1767 GSList *resources, *p_res;
1768 char *bstr = "unknown";
1769
1770 // Enter chat mode
1771 scr_set_chatmode(TRUE);
1772 scr_ShowBuddyWindow();
1773
1774 snprintf(buffer, 4095, "jid: <%s>", bjid);
1775 scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
1776 if (name) {
1777 snprintf(buffer, 4095, "Name: %s", name);
1778 scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
1779 }
1780
1781 if (type == ROSTER_TYPE_USER) bstr = "user";
1782 else if (type == ROSTER_TYPE_ROOM) bstr = "chatroom";
1783 else if (type == ROSTER_TYPE_AGENT) bstr = "agent";
1784 snprintf(buffer, 127, "Type: %s", bstr);
1785 scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
1786
1787 if (!on_srv) {
1788 scr_WriteIncomingMessage(bjid, "(Local item, not on the server)",
1789 0, HBB_PREFIX_INFO, 0);
1790 }
1791
1792 if (esub == sub_both) bstr = "both";
1793 else if (esub & sub_from) bstr = "from";
1794 else if (esub & sub_to) bstr = "to";
1795 else bstr = "none";
1796 snprintf(buffer, 64, "Subscription: %s", bstr);
1797 if (esub & sub_pending)
1798 strcat(buffer, " (pending)");
1799 scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
1800
1801 resources = buddy_getresources(bud);
1802 if (!resources && type == ROSTER_TYPE_USER) {
1803 // No resource; display last status message, if any.
1804 const char *rst_msg = buddy_getstatusmsg(bud, "");
1805 if (rst_msg) {
1806 snprintf(buffer, 4095, "Last status message: %s", rst_msg);
1807 scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
1808 }
1809 }
1810 for (p_res = resources ; p_res ; p_res = g_slist_next(p_res)) {
1811 gchar rprio;
1812 enum imstatus rstatus;
1813 const char *rst_msg;
1814 time_t rst_time;
1815 struct pgp_data *rpgp;
1816
1817 rprio = buddy_getresourceprio(bud, p_res->data);
1818 rstatus = buddy_getstatus(bud, p_res->data);
1819 rst_msg = buddy_getstatusmsg(bud, p_res->data);
1820 rst_time = buddy_getstatustime(bud, p_res->data);
1821 rpgp = buddy_resource_pgp(bud, p_res->data);
1822
1823 snprintf(buffer, 4095, "Resource: [%c] (%d) %s", imstatus2char[rstatus],
1824 rprio, (char*)p_res->data);
1825 scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
1826 if (rst_msg) {
1827 snprintf(buffer, 4095, "Status message: %s", rst_msg);
1828 scr_WriteIncomingMessage(bjid, buffer,
1829 0, HBB_PREFIX_INFO | HBB_PREFIX_CONT, 0);
1830 }
1831 if (rst_time) {
1832 char tbuf[128];
1833
1834 strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", localtime(&rst_time));
1835 snprintf(buffer, 127, "Status timestamp: %s", tbuf);
1836 scr_WriteIncomingMessage(bjid, buffer,
1837 0, HBB_PREFIX_INFO | HBB_PREFIX_CONT, 0);
1838 }
1839 #ifdef HAVE_GPGME
1840 if (rpgp && rpgp->sign_keyid) {
1841 snprintf(buffer, 4095, "PGP key id: %s", rpgp->sign_keyid);
1842 scr_WriteIncomingMessage(bjid, buffer,
1843 0, HBB_PREFIX_INFO | HBB_PREFIX_CONT, 0);
1844 if (rpgp->last_sigsum) {
1845 gpgme_sigsum_t ss = rpgp->last_sigsum;
1846 snprintf(buffer, 4095, "Last PGP signature: %s",
1847 (ss & GPGME_SIGSUM_GREEN ? "good":
1848 (ss & GPGME_SIGSUM_RED ? "bad" : "unknown")));
1849 scr_WriteIncomingMessage(bjid, buffer,
1850 0, HBB_PREFIX_INFO | HBB_PREFIX_CONT, 0);
1851 }
1852 }
1853 #endif
1854 g_free(p_res->data);
1855 }
1856 g_slist_free(resources);
1857 } else { /* Item has no jid */
1858 if (name) scr_LogPrint(LPRINT_NORMAL, "Name: %s", name);
1859 scr_LogPrint(LPRINT_NORMAL, "Type: %s",
1860 type == ROSTER_TYPE_GROUP ? "group" :
1861 (type == ROSTER_TYPE_SPECIAL ? "special" : "unknown"));
1862 }
1863 g_free(buffer);
1864
1865 // Tell the user if this item has an annotation.
1866 if (type == ROSTER_TYPE_USER ||
1867 type == ROSTER_TYPE_ROOM ||
1868 type == ROSTER_TYPE_AGENT) {
1869 struct annotation *note = xmpp_get_storage_rosternotes(bjid, TRUE);
1870 if (note) {
1871 // We do not display the note, we just tell the user.
1872 g_free(note->text);
1873 g_free(note->jid);
1874 g_free(note);
1875 scr_WriteIncomingMessage(bjid, "(This item has an annotation)", 0,
1876 HBB_PREFIX_INFO, 0);
1877 }
1878 }
1879 }
1880
1881 // room_names() is a variation of do_info(), for chatrooms only
1882 static void room_names(gpointer bud, char *arg)
1883 {
1884 const char *bjid;
1885 char *buffer;
1886 GSList *resources, *p_res;
1887 enum { style_normal = 0, style_detail, style_short,
1888 style_quiet, style_compact } style = 0;
1889
1890 if (*arg) {
1891 if (!strcasecmp(arg, "--short"))
1892 style = style_short;
1893 else if (!strcasecmp(arg, "--quiet"))
1894 style = style_quiet;
1895 else if (!strcasecmp(arg, "--detail"))
1896 style = style_detail;
1897 else if (!strcasecmp(arg, "--compact"))
1898 style = style_compact;
1899 else {
1900 scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
1901 return;
1902 }
1903 }
1904
1905 // Enter chat mode
1906 scr_set_chatmode(TRUE);
1907 scr_ShowBuddyWindow();
1908
1909 bjid = buddy_getjid(bud);
1910
1911 buffer = g_new(char, 4096);
1912 strncpy(buffer, "Room members:", 127);
1913 scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
1914
1915 resources = buddy_getresources(bud);
1916 for (p_res = resources ; p_res ; p_res = g_slist_next(p_res)) {
1917 enum imstatus rstatus;
1918 const char *rst_msg;
1919
1920 rstatus = buddy_getstatus(bud, p_res->data);
1921 rst_msg = buddy_getstatusmsg(bud, p_res->data);
1922
1923 if (style == style_short) {
1924 snprintf(buffer, 4095, "[%c] %s%s%s", imstatus2char[rstatus],
1925 (char*)p_res->data,
1926 rst_msg ? " -- " : "", rst_msg ? rst_msg : "");
1927 scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
1928 } else if (style == style_compact) {
1929 enum imrole role = buddy_getrole(bud, p_res->data);
1930 enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
1931 bool showaffil = (affil != affil_none);
1932
1933 snprintf(buffer, 4095, "[%c] %s (%s%s%s)",
1934 imstatus2char[rstatus], (char*)p_res->data,
1935 showaffil ? straffil[affil] : "\0",
1936 showaffil ? "/" : "\0",
1937 strrole[role]);
1938 scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
1939 } else {
1940 // (Style "normal", "detail" or "quiet")
1941 snprintf(buffer, 4095, "[%c] %s", imstatus2char[rstatus],
1942 (char*)p_res->data);
1943 scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
1944 if (rst_msg && style != style_quiet) {
1945 snprintf(buffer, 4095, "Status message: %s", rst_msg);
1946 scr_WriteIncomingMessage(bjid, buffer,
1947 0, HBB_PREFIX_INFO | HBB_PREFIX_CONT, 0);
1948 }
1949 if (style == style_detail) {
1950 enum imrole role = buddy_getrole(bud, p_res->data);
1951 enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
1952
1953 snprintf(buffer, 4095, "Role: %s", strrole[role]);
1954 scr_WriteIncomingMessage(bjid, buffer,
1955 0, HBB_PREFIX_INFO | HBB_PREFIX_CONT, 0);
1956 if (affil != affil_none) {
1957 snprintf(buffer, 4095, "Affiliat.: %s", straffil[affil]);
1958 scr_WriteIncomingMessage(bjid, buffer,
1959 0, HBB_PREFIX_INFO | HBB_PREFIX_CONT, 0);
1960 }
1961 }
1962 }
1963 g_free(p_res->data);
1964 }
1965 g_slist_free(resources);
1966 g_free(buffer);
1967 }
1968
1969 static void move_group_member(gpointer bud, void *groupnamedata)
1970 {
1971 const char *bjid, *name, *groupname;
1972
1973 groupname = (char *)groupnamedata;
1974
1975 bjid = buddy_getjid(bud);
1976 name = buddy_getname(bud);
1977
1978 xmpp_updatebuddy(bjid, name, *groupname ? groupname : NULL);
1979 }
1980
1981 static void do_rename(char *arg)
1982 {
1983 gpointer bud;
1984 const char *bjid, *group;
1985 guint type, on_srv;
1986 char *newname, *p;
1987 char *name_utf8;
1988
1989 if (!current_buddy)
1990 return;
1991 bud = BUDDATA(current_buddy);
1992
1993 bjid = buddy_getjid(bud);
1994 group = buddy_getgroupname(bud);
1995 type = buddy_gettype(bud);
1996 on_srv = buddy_getonserverflag(bud);
1997
1998 if (type & ROSTER_TYPE_SPECIAL) {
1999 scr_LogPrint(LPRINT_NORMAL, "You can't rename this item.");
2000 return;
2001 }
2002
2003 if (!*arg && !(type & ROSTER_TYPE_GROUP)) {
2004 scr_LogPrint(LPRINT_NORMAL, "Please specify a new name.");
2005 return;
2006 }
2007
2008 if (!(type & ROSTER_TYPE_GROUP) && !on_srv) {
2009 scr_LogPrint(LPRINT_NORMAL,
2010 "Note: this item will be added to your server roster.");
2011 // If this is a MUC room w/o bookmark, let's give a small hint...
2012 if ((type & ROSTER_TYPE_ROOM) && !xmpp_is_bookmarked(bjid)) {
2013 scr_LogPrint(LPRINT_NORMAL,
2014 "You should add a room bookmark or it will not be "
2015 "recognized as a MUC room next time you run mcabber.");
2016 }
2017 }
2018
2019 newname = g_strdup(arg);
2020 // Remove trailing space
2021 for (p = newname; *p; p++) ;
2022 while (p > newname && *p == ' ') *p = 0;
2023
2024 strip_arg_special_chars(newname);
2025
2026 name_utf8 = to_utf8(newname);
2027
2028 if (type & ROSTER_TYPE_GROUP) {
2029 // Rename a whole group
2030 foreach_group_member(bud, &move_group_member, name_utf8);
2031 // Let's jump to the previous buddy, because this group name should
2032 // disappear when we receive the server answer.
2033 scr_RosterUpDown(-1, 1);
2034 } else {
2035 // Rename a single buddy
2036 guint del_name = 0;
2037 if (!*newname || !strcmp(arg, "-"))
2038 del_name = TRUE;
2039 buddy_setname(bud, (del_name ? (char*)bjid : name_utf8));
2040 xmpp_updatebuddy(bjid, (del_name ? NULL : name_utf8), group);
2041 }
2042
2043 g_free(name_utf8);
2044 g_free(newname);
2045 update_roster = TRUE;
2046 }
2047
2048 static void do_move(char *arg)
2049 {
2050 gpointer bud;
2051 const char *bjid, *name, *oldgroupname;
2052 guint type;
2053 char *newgroupname, *p;
2054 char *group_utf8;
2055
2056 if (!current_buddy)
2057 return;
2058 bud = BUDDATA(current_buddy);
2059
2060 bjid = buddy_getjid(bud);
2061 name = buddy_getname(bud);
2062 type = buddy_gettype(bud);
2063
2064 oldgroupname = buddy_getgroupname(bud);
2065
2066 if (type & ROSTER_TYPE_GROUP) {
2067 scr_LogPrint(LPRINT_NORMAL, "You can't move groups!");
2068 return;
2069 }
2070 if (type & ROSTER_TYPE_SPECIAL) {
2071 scr_LogPrint(LPRINT_NORMAL, "You can't move this item.");
2072 return;
2073 }
2074
2075 newgroupname = g_strdup(arg);
2076 // Remove trailing space
2077 for (p = newgroupname; *p; p++) ;
2078 while (p > newgroupname && *p == ' ') *p-- = 0;
2079
2080 strip_arg_special_chars(newgroupname);
2081
2082 group_utf8 = to_utf8(newgroupname);
2083 if (strcmp(oldgroupname, group_utf8)) {
2084 guint msgflag;
2085
2086 xmpp_updatebuddy(bjid, name, *group_utf8 ? group_utf8 : NULL);
2087 scr_RosterUpDown(-1, 1);
2088
2089 // If the buddy has a pending message flag,
2090 // we remove it temporarily in order to reset the global group
2091 // flag. We set it back once the buddy is in the new group,
2092 // which will update the new group's flag.
2093 msgflag = buddy_getflags(bud) & ROSTER_FLAG_MSG;
2094 if (msgflag)
2095 roster_msg_setflag(bjid, FALSE, FALSE);
2096 buddy_setgroup(bud, group_utf8);
2097 if (msgflag)
2098 roster_msg_setflag(bjid, FALSE, TRUE);
2099 }
2100
2101 g_free(group_utf8);
2102 g_free(newgroupname);
2103 update_roster = TRUE;
2104 }
2105
2106 static void print_option_cb(char *k, char *v, void *f)
2107 {
2108 char *format = (char *)f;
2109 scr_LogPrint (LPRINT_NORMAL, format, k, v);
2110 }
2111
2112 static void do_set(char *arg)
2113 {
2114 guint assign;
2115 gchar *option, *value;
2116 gchar *option_utf8;
2117
2118 if (!*arg) {
2119 // list all set options
2120 settings_foreach(SETTINGS_TYPE_OPTION, print_option_cb, "%s = [%s]");
2121 return;
2122 }
2123
2124 assign = parse_assigment(arg, &option, &value);
2125 if (!option) {
2126 scr_LogPrint(LPRINT_NORMAL, "Set what option?");
2127 return;
2128 }
2129 option_utf8 = to_utf8(option);
2130 g_free(option);
2131 if (!assign) { // This is a query
2132 const char *val = settings_opt_get(option_utf8);
2133 if (val)
2134 scr_LogPrint(LPRINT_NORMAL, "%s = [%s]", option_utf8, val);
2135 else
2136 scr_LogPrint(LPRINT_NORMAL, "Option %s is not set", option_utf8);
2137 g_free(option_utf8);
2138 return;
2139 }
2140 // Update the option
2141 // Maybe some options should be protected when user is connected (server,
2142 // username, etc.). And we should catch some options here, too
2143 // (hide_offline_buddies for ex.)
2144 if (!value) {
2145 settings_del(SETTINGS_TYPE_OPTION, option_utf8);
2146 } else {
2147 gchar *value_utf8 = to_utf8(value);
2148 settings_set(SETTINGS_TYPE_OPTION, option_utf8, value_utf8);
2149 g_free(value_utf8);
2150 g_free(value);
2151 }
2152 g_free(option_utf8);
2153 }
2154
2155 static void dump_alias(char *k, char *v, void *param)
2156 {
2157 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8, "Alias %s = %s", k, v);
2158 }
2159
2160 static void do_alias(char *arg)
2161 {
2162 guint assign;
2163 gchar *alias, *value;
2164
2165 assign = parse_assigment(arg, &alias, &value);
2166 if (!alias) {
2167 settings_foreach(SETTINGS_TYPE_ALIAS, &dump_alias, NULL);
2168 return;
2169 }
2170 if (!assign) { // This is a query
2171 const char *val = settings_get(SETTINGS_TYPE_ALIAS, alias);
2172 // NOTE: LPRINT_NOTUTF8 here, see below why it isn't encoded...
2173 if (val)
2174 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8, "%s = %s", alias, val);
2175 else
2176 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
2177 "Alias '%s' does not exist", alias);
2178 goto do_alias_return;
2179 }
2180 // Check the alias does not conflict with a registered command
2181 if (cmd_get(alias)) {
2182 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
2183 "'%s' is a reserved word!", alias);
2184 goto do_alias_return;
2185 }
2186 // Update the alias
2187 if (!value) {
2188 if (settings_get(SETTINGS_TYPE_ALIAS, alias)) {
2189 settings_del(SETTINGS_TYPE_ALIAS, alias);
2190 // Remove alias from the completion list
2191 compl_del_category_word(COMPL_CMD, alias);
2192 }
2193 } else {
2194 /* Add alias to the completion list, if not already in.
2195 NOTE: We're not UTF8-encoding "alias" and "value" here because UTF-8 is
2196 not yet supported in the UI... (and we use the values in the completion
2197 system)
2198 */
2199 if (!settings_get(SETTINGS_TYPE_ALIAS, alias))
2200 compl_add_category_word(COMPL_CMD, alias);
2201 settings_set(SETTINGS_TYPE_ALIAS, alias, value);
2202 g_free(value);
2203 }
2204 do_alias_return:
2205 g_free(alias);
2206 }
2207
2208 static void dump_bind(char *k, char *v, void *param)
2209 {
2210 scr_LogPrint(LPRINT_NORMAL, "Key %4s is bound to: %s", k, v);
2211 }
2212
2213 static void do_bind(char *arg)
2214 {
2215 guint assign;
2216 gchar *k_code, *value;
2217
2218 assign = parse_assigment(arg, &k_code, &value);
2219 if (!k_code) {
2220 settings_foreach(SETTINGS_TYPE_BINDING, &dump_bind, NULL);
2221 return;
2222 }
2223 if (!assign) { // This is a query
2224 const char *val = settings_get(SETTINGS_TYPE_BINDING, k_code);
2225 if (val)
2226 scr_LogPrint(LPRINT_NORMAL, "Key %s is bound to: %s", k_code, val);
2227 else
2228 scr_LogPrint(LPRINT_NORMAL, "Key %s is not bound.", k_code);
2229 g_free(k_code);
2230 return;
2231 }
2232 // Update the key binding
2233 if (!value) {
2234 settings_del(SETTINGS_TYPE_BINDING, k_code);
2235 } else {
2236 gchar *value_utf8 = to_utf8(value);
2237 settings_set(SETTINGS_TYPE_BINDING, k_code, value_utf8);
2238 g_free(value_utf8);
2239 g_free(value);
2240 }
2241 g_free(k_code);
2242 }
2243
2244 static void do_rawxml(char *arg)
2245 {
2246 char **paramlst;
2247 char *subcmd;
2248
2249 if (!lm_connection_is_authenticated(lconnection)) {
2250 scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
2251 return;
2252 }
2253
2254 paramlst = split_arg(arg, 2, 1); // subcmd, arg
2255 subcmd = *paramlst;
2256 arg = *(paramlst+1);
2257
2258 if (!subcmd || !*subcmd) {
2259 scr_LogPrint(LPRINT_NORMAL, "Please read the manual page"
2260 " before using /rawxml :-)");
2261 free_arg_lst(paramlst);
2262 return;
2263 }
2264
2265 if (!strcasecmp(subcmd, "send")) {
2266 gchar *buffer;
2267
2268 if (!subcmd || !*subcmd) {
2269 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
2270 free_arg_lst(paramlst);
2271 return;
2272 }
2273
2274 // We don't strip_arg_special_chars() here, because it would be a pain for
2275 // the user to escape quotes in a XML stream...
2276
2277 buffer = to_utf8(arg);
2278 if (buffer) {
2279 scr_LogPrint(LPRINT_NORMAL, "Sending XML string");
2280 lm_connection_send_raw(lconnection, buffer, NULL);
2281 g_free(buffer);
2282 } else {
2283 scr_LogPrint(LPRINT_NORMAL, "Conversion error in XML string.");
2284 }
2285 } else {
2286 scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
2287 }
2288
2289 free_arg_lst(paramlst);
2290 }
2291
2292 // check_room_subcommand(arg, param_needed, buddy_must_be_a_room)
2293 // - Check if this is a room, if buddy_must_be_a_room is not null
2294 // - Check there is at least 1 parameter, if param_needed is true
2295 // - Return null if one of the checks fails, or a pointer to the first
2296 // non-space character.
2297 static char *check_room_subcommand(char *arg, bool param_needed,
2298 gpointer buddy_must_be_a_room)
2299 {
2300 if (buddy_must_be_a_room &&
2301 !(buddy_gettype(buddy_must_be_a_room) & ROSTER_TYPE_ROOM)) {
2302 scr_LogPrint(LPRINT_NORMAL, "This isn't a conference room.");
2303 return NULL;
2304 }
2305
2306 if (param_needed) {
2307 if (!arg) {
2308 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
2309 return NULL;
2310 }
2311 }
2312
2313 if (arg)
2314 return arg;
2315 else
2316 return "";
2317 }
2318
2319 static void room_join(gpointer bud, char *arg)
2320 {
2321 char **paramlst;
2322 char *roomname, *nick, *pass;
2323 char *roomname_tmp = NULL;
2324 char *pass_utf8;
2325
2326 paramlst = split_arg(arg, 3, 0); // roomid, nickname, password
2327 roomname = *paramlst;
2328 nick = *(paramlst+1);
2329 pass = *(paramlst+2);
2330
2331 if (!roomname)
2332 nick = NULL;
2333 if (!nick)
2334 pass = NULL;
2335
2336 if (!roomname || !strcmp(roomname, ".")) {
2337 // If the current_buddy is recognized as a room, the room name
2338 // can be omitted (or "." can be used).
2339 if (!bud || !(buddy_gettype(bud) & ROSTER_TYPE_ROOM)) {
2340 scr_LogPrint(LPRINT_NORMAL, "Please specify a room name.");
2341 free_arg_lst(paramlst);
2342 return;
2343 }
2344 roomname = (char*)buddy_getjid(bud);
2345 } else if (strchr(roomname, '/')) {
2346 scr_LogPrint(LPRINT_NORMAL, "Invalid room name.");
2347 free_arg_lst(paramlst);
2348 return;
2349 } else {
2350 // The room id has been specified. Let's convert it and use it.
2351 mc_strtolower(roomname);
2352 roomname = roomname_tmp = to_utf8(roomname);
2353 }
2354
2355 // If no nickname is provided with the /join command,
2356 // we try to get a default nickname.
2357 if (!nick || !*nick)
2358 nick = default_muc_nickname(roomname);
2359 else
2360 nick = to_utf8(nick);
2361 // If we still have no nickname, give up
2362 if (!nick || !*nick) {
2363 scr_LogPrint(LPRINT_NORMAL, "Please specify a nickname.");
2364 g_free(nick);
2365 free_arg_lst(paramlst);
2366 return;
2367 }
2368
2369 pass_utf8 = to_utf8(pass);
2370
2371 xmpp_room_join(roomname, nick, pass_utf8);
2372
2373 scr_LogPrint(LPRINT_LOGNORM, "Sent a join request to <%s>...", roomname);
2374
2375 g_free(roomname_tmp);
2376 g_free(nick);
2377 g_free(pass_utf8);
2378 buddylist_build();
2379 update_roster = TRUE;
2380 free_arg_lst(paramlst);
2381 }
2382
2383 static void room_invite(gpointer bud, char *arg)
2384 {
2385 char **paramlst;
2386 const gchar *roomname;
2387 char* fjid;
2388 gchar *reason_utf8;
2389
2390 paramlst = split_arg(arg, 2, 1); // jid, [reason]
2391 fjid = *paramlst;
2392 arg = *(paramlst+1);
2393 // An empty reason is no reason...
2394 if (arg && !*arg)
2395 arg = NULL;
2396
2397 if (!fjid || !*fjid) {
2398 scr_LogPrint(LPRINT_NORMAL, "Missing or incorrect Jabber ID.");
2399 free_arg_lst(paramlst);
2400 return;
2401 }
2402
2403 roomname = buddy_getjid(bud);
2404 reason_utf8 = to_utf8(arg);
2405 xmpp_room_invite(roomname, fjid, reason_utf8);
2406 scr_LogPrint(LPRINT_LOGNORM, "Invitation sent to <%s>.", fjid);
2407 g_free(reason_utf8);
2408 free_arg_lst(paramlst);
2409 }
2410
2411 static void room_affil(gpointer bud, char *arg)
2412 {
2413 char **paramlst;
2414 gchar *fjid, *rolename;
2415 struct role_affil ra;
2416 const char *roomid = buddy_getjid(bud);
2417
2418 paramlst = split_arg(arg, 3, 1); // jid, new_affil, [reason]
2419 fjid = *paramlst;
2420 rolename = *(paramlst+1);
2421 arg = *(paramlst+2);
2422
2423 if (!fjid || !*fjid || !rolename || !*rolename) {
2424 scr_LogPrint(LPRINT_NORMAL, "Please specify both a Jabber ID and a role.");
2425 free_arg_lst(paramlst);
2426 return;
2427 }
2428
2429 ra.type = type_affil;
2430 ra.val.affil = affil_none;
2431 for (; ra.val.affil < imaffiliation_size; ra.val.affil++)
2432 if (!strcasecmp(rolename, straffil[ra.val.affil]))
2433 break;
2434
2435 if (ra.val.affil < imaffiliation_size) {
2436 gchar *jid_utf8, *reason_utf8;
2437 jid_utf8 = to_utf8(fjid);
2438 reason_utf8 = to_utf8(arg);
2439 xmpp_room_setattrib(roomid, jid_utf8, NULL, ra, reason_utf8);
2440 g_free(jid_utf8);
2441 g_free(reason_utf8);
2442 } else
2443 scr_LogPrint(LPRINT_NORMAL, "Wrong affiliation parameter.");
2444
2445 free_arg_lst(paramlst);
2446 }
2447
2448 static void room_role(gpointer bud, char *arg)
2449 {
2450 char **paramlst;
2451 gchar *fjid, *rolename;
2452 struct role_affil ra;
2453 const char *roomid = buddy_getjid(bud);
2454
2455 paramlst = split_arg(arg, 3, 1); // jid, new_role, [reason]
2456 fjid = *paramlst;
2457 rolename = *(paramlst+1);
2458 arg = *(paramlst+2);
2459
2460 if (!fjid || !*fjid || !rolename || !*rolename) {
2461 scr_LogPrint(LPRINT_NORMAL, "Please specify both a Jabber ID and a role.");
2462 free_arg_lst(paramlst);
2463 return;
2464 }
2465
2466 ra.type = type_role;
2467 ra.val.role = role_none;
2468 for (; ra.val.role < imrole_size; ra.val.role++)
2469 if (!strcasecmp(rolename, strrole[ra.val.role]))
2470 break;
2471
2472 if (ra.val.role < imrole_size) {
2473 gchar *jid_utf8, *reason_utf8;
2474 jid_utf8 = to_utf8(fjid);
2475 reason_utf8 = to_utf8(arg);
2476 xmpp_room_setattrib(roomid, jid_utf8, NULL, ra, reason_utf8);
2477 g_free(jid_utf8);
2478 g_free(reason_utf8);
2479 } else
2480 scr_LogPrint(LPRINT_NORMAL, "Wrong role parameter.");
2481
2482 free_arg_lst(paramlst);
2483 }
2484
2485
2486 // The expected argument is a Jabber id
2487 static void room_ban(gpointer bud, char *arg)
2488 {
2489 char **paramlst;
2490 gchar *fjid, *bjid;
2491 const gchar *banjid;
2492 gchar *jid_utf8, *reason_utf8;
2493 struct role_affil ra;
2494 const char *roomid = buddy_getjid(bud);
2495
2496 paramlst = split_arg(arg, 2, 1); // jid, [reason]
2497 fjid = *paramlst;
2498 arg = *(paramlst+1);
2499
2500 if (!fjid || !*fjid) {
2501 scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
2502 free_arg_lst(paramlst);
2503 return;
2504 }
2505
2506 ra.type = type_affil;
2507 ra.val.affil = affil_outcast;
2508
2509 bjid = jidtodisp(fjid);
2510 jid_utf8 = to_utf8(bjid);
2511
2512 // If the argument doesn't look like a jid, we'll try to find a matching
2513 // nickname.
2514 if (!strchr(bjid, JID_DOMAIN_SEPARATOR) || check_jid_syntax(bjid)) {
2515 const gchar *tmp;
2516 // We want the initial argument, so the fjid variable, because
2517 // we don't want to strip a resource-like string from the nickname!
2518 g_free(jid_utf8);
2519 jid_utf8 = to_utf8(fjid);
2520 tmp = buddy_getrjid(bud, jid_utf8);
2521 if (!tmp) {
2522 scr_LogPrint(LPRINT_NORMAL, "Wrong JID or nickname");
2523 goto room_ban_return;
2524 }
2525 banjid = jidtodisp(tmp);
2526 } else
2527 banjid = jid_utf8;
2528
2529 scr_LogPrint(LPRINT_NORMAL, "Requesting a ban for %s", banjid);
2530
2531 reason_utf8 = to_utf8(arg);
2532 xmpp_room_setattrib(roomid, banjid, NULL, ra, reason_utf8);
2533 g_free(reason_utf8);
2534
2535 room_ban_return:
2536 g_free(bjid);
2537 g_free(jid_utf8);
2538 free_arg_lst(paramlst);
2539 }
2540
2541 // The expected argument is a Jabber id
2542 static void room_unban(gpointer bud, char *arg)
2543 {
2544 gchar *fjid = arg;
2545 gchar *jid_utf8;
2546 struct role_affil ra;
2547 const char *roomid = buddy_getjid(bud);
2548
2549 if (!fjid || !*fjid) {
2550 scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
2551 return;
2552 }
2553
2554 ra.type = type_affil;
2555 ra.val.affil = affil_none;
2556
2557 jid_utf8 = to_utf8(fjid);
2558 xmpp_room_setattrib(roomid, jid_utf8, NULL, ra, NULL);
2559 g_free(jid_utf8);
2560 }
2561
2562 // The expected argument is a nickname
2563 static void room_kick(gpointer bud, char *arg)
2564 {
2565 char **paramlst;
2566 gchar *nick;
2567 gchar *nick_utf8, *reason_utf8;
2568 struct role_affil ra;
2569 const char *roomid = buddy_getjid(bud);
2570
2571 paramlst = split_arg(arg, 2, 1); // nickname, [reason]
2572 nick = *paramlst;
2573 arg = *(paramlst+1);
2574
2575 if (!nick || !*nick) {
2576 scr_LogPrint(LPRINT_NORMAL, "Please specify a nickname.");
2577 free_arg_lst(paramlst);
2578 return;
2579 }
2580
2581 ra.type = type_role;
2582 ra.val.affil = role_none;
2583
2584 nick_utf8 = to_utf8(nick);
2585 reason_utf8 = to_utf8(arg);
2586 xmpp_room_setattrib(roomid, NULL, nick_utf8, ra, reason_utf8);
2587 g_free(nick_utf8);
2588 g_free(reason_utf8);
2589
2590 free_arg_lst(paramlst);
2591 }
2592
2593 void cmd_room_leave(gpointer bud, char *arg)
2594 {
2595 gchar *roomid, *desc;
2596 const char *nickname;
2597
2598 nickname = buddy_getnickname(bud);
2599 if (!nickname) {
2600 scr_LogPrint(LPRINT_NORMAL, "You are not in this room.");
2601 return;
2602 }
2603
2604 roomid = g_strdup_printf("%s/%s", buddy_getjid(bud), nickname);
2605 desc = to_utf8(arg);
2606 xmpp_setstatus(offline, roomid, desc, TRUE);
2607 g_free(desc);
2608 g_free(roomid);
2609 }
2610
2611 static void room_nick(gpointer bud, char *arg)
2612 {
2613 if (!buddy_getinsideroom(bud)) {
2614 scr_LogPrint(LPRINT_NORMAL, "You are not in this room.");
2615 return;
2616 }
2617
2618 if (!arg || !*arg) {
2619 const char *nick = buddy_getnickname(bud);
2620 if (nick)
2621 scr_LogPrint(LPRINT_NORMAL, "Your nickname is: %s", nick);
2622 else
2623 scr_LogPrint(LPRINT_NORMAL, "You have no nickname in this room.");
2624 } else {
2625 gchar *nick = to_utf8(arg);
2626 strip_arg_special_chars(nick);
2627 xmpp_room_join(buddy_getjid(bud), nick, NULL);
2628 g_free(nick);
2629 }
2630 }
2631
2632 static void room_privmsg(gpointer bud, char *arg)
2633 {
2634 char **paramlst;
2635 gchar *fjid_utf8, *nick, *nick_utf8, *msg;
2636
2637 paramlst = split_arg(arg, 2, 1); // nickname, message
2638 nick = *paramlst;
2639 arg = *(paramlst+1);
2640
2641 if (!nick || !*nick || !arg || !*arg) {
2642 scr_LogPrint(LPRINT_NORMAL,
2643 "Please specify both a Jabber ID and a message.");
2644 free_arg_lst(paramlst);
2645 return;
2646 }
2647
2648 nick_utf8 = to_utf8(nick);
2649 fjid_utf8 = g_strdup_printf("%s/%s", buddy_getjid(bud), nick_utf8);
2650 g_free (nick_utf8);
2651 msg = to_utf8(arg);
2652 send_message_to(fjid_utf8, msg, NULL, LM_MESSAGE_SUB_TYPE_NOT_SET, FALSE);
2653 g_free(fjid_utf8);
2654 g_free(msg);
2655 free_arg_lst(paramlst);
2656 }
2657
2658 static void room_remove(gpointer bud, char *arg)
2659 {
2660 if (*arg) {
2661 scr_LogPrint(LPRINT_NORMAL, "This action does not require a parameter; "
2662 "the currently-selected room will be removed.");
2663 return;
2664 }
2665
2666 // Quick check: if there are resources, we haven't left
2667 if (buddy_getinsideroom(bud)) {
2668 scr_LogPrint(LPRINT_NORMAL, "You haven't left this room!");
2669 return;
2670 }
2671 // Delete the room
2672 roster_del_user(buddy_getjid(bud));
2673 scr_UpdateBuddyWindow();
2674 buddylist_build();
2675 update_roster = TRUE;
2676 }
2677
2678 static void room_topic(gpointer bud, char *arg)
2679 {
2680 if (!buddy_getinsideroom(bud)) {
2681 scr_LogPrint(LPRINT_NORMAL, "You are not in this room.");
2682 return;
2683 }
2684
2685 // If no parameter is given, display the current topic
2686 if (!*arg) {
2687 const char *topic = buddy_gettopic(bud);
2688 if (topic)
2689 scr_LogPrint(LPRINT_NORMAL, "Topic: %s", topic);
2690 else
2691 scr_LogPrint(LPRINT_NORMAL, "No topic has been set.");
2692 return;
2693 }
2694
2695 // If arg is "-", let's clear the topic
2696 if (!strcmp(arg, "-"))
2697 arg = NULL;
2698
2699 arg = to_utf8(arg);
2700 // Set the topic
2701 xmpp_send_msg(buddy_getjid(bud), NULL, ROSTER_TYPE_ROOM, arg ? arg : "",
2702 FALSE, NULL, LM_MESSAGE_SUB_TYPE_NOT_SET, NULL);
2703 g_free(arg);
2704 }
2705
2706 static void room_destroy(gpointer bud, char *arg)
2707 {
2708 gchar *msg;
2709
2710 if (arg && *arg)
2711 msg = to_utf8(arg);
2712 else
2713 msg = NULL;
2714
2715 xmpp_room_destroy(buddy_getjid(bud), NULL, msg);
2716 g_free(msg);
2717 }
2718
2719 static void room_unlock(gpointer bud, char *arg)
2720 {
2721 if (*arg) {
2722 scr_LogPrint(LPRINT_NORMAL, "Unknown parameter.");
2723 return;
2724 }
2725
2726 xmpp_room_unlock(buddy_getjid(bud));
2727 }
2728
2729 static void room_setopt(gpointer bud, char *arg)
2730 {
2731 char **paramlst;
2732 char *param, *value;
2733 enum { opt_none = 0, opt_printstatus, opt_autowhois } option = 0;
2734
2735 paramlst = split_arg(arg, 2, 1); // param, value
2736 param = *paramlst;
2737 value = *(paramlst+1);
2738 if (!param) {
2739 scr_LogPrint(LPRINT_NORMAL, "Please specify a room option.");
2740 free_arg_lst(paramlst);
2741 return;
2742 }
2743
2744 if (!strcasecmp(param, "print_status"))
2745 option = opt_printstatus;
2746 else if (!strcasecmp(param, "auto_whois"))
2747 option = opt_autowhois;
2748 else {
2749 scr_LogPrint(LPRINT_NORMAL, "Wrong option!");
2750 free_arg_lst(paramlst);
2751 return;
2752 }
2753
2754 // If no value is given, display the current value
2755 if (!value) {
2756 const char *strval;
2757 if (option == opt_printstatus)
2758 strval = strprintstatus[buddy_getprintstatus(bud)];
2759 else
2760 strval = strautowhois[buddy_getautowhois(bud)];
2761 scr_LogPrint(LPRINT_NORMAL, "%s is set to: %s", param, strval);
2762 free_arg_lst(paramlst);
2763 return;
2764 }
2765
2766 if (option == opt_printstatus) {
2767 enum room_printstatus eval;
2768 if (!strcasecmp(value, "none"))
2769 eval = status_none;
2770 else if (!strcasecmp(value, "in_and_out"))
2771 eval = status_in_and_out;
2772 else if (!strcasecmp(value, "all"))
2773 eval = status_all;
2774 else {
2775 eval = status_default;
2776 if (strcasecmp(value, "default") != 0)
2777 scr_LogPrint(LPRINT_NORMAL, "Unrecognized value, assuming default...");
2778 }
2779 buddy_setprintstatus(bud, eval);
2780 } else if (option == opt_autowhois) {
2781 enum room_autowhois eval;
2782 if (!strcasecmp(value, "on"))
2783 eval = autowhois_on;
2784 else if (!strcasecmp(value, "off"))
2785 eval = autowhois_off;
2786 else {
2787 eval = autowhois_default;
2788 if (strcasecmp(value, "default") != 0)
2789 scr_LogPrint(LPRINT_NORMAL, "Unrecognized value, assuming default...");
2790 }
2791 buddy_setautowhois(bud, eval);
2792 }
2793
2794 free_arg_lst(paramlst);
2795 }
2796
2797 // cmd_room_whois(..)
2798 // If interactive is TRUE, chatmode can be enabled.
2799 void cmd_room_whois(gpointer bud, char *arg, guint interactive)
2800 {
2801 char **paramlst;
2802 gchar *nick, *buffer;
2803 const char *bjid, *realjid;
2804 const char *rst_msg;
2805 gchar rprio;
2806 enum imstatus rstatus;
2807 enum imrole role;
2808 enum imaffiliation affil;
2809 time_t rst_time;
2810 guint msg_flag = HBB_PREFIX_INFO;
2811
2812 paramlst = split_arg(arg, 1, 0); // nickname
2813 nick = *paramlst;
2814
2815 if (!nick || !*nick) {
2816 scr_LogPrint(LPRINT_NORMAL, "Please specify a nickname.");
2817 free_arg_lst(paramlst);
2818 return;
2819 }
2820
2821 nick = to_utf8(nick);
2822
2823 if (interactive) {
2824 // Enter chat mode
2825 scr_set_chatmode(TRUE);
2826 scr_ShowBuddyWindow();
2827 } else
2828 msg_flag |= HBB_PREFIX_NOFLAG;
2829
2830 bjid = buddy_getjid(bud);
2831 rstatus = buddy_getstatus(bud, nick);
2832
2833 if (rstatus == offline) {
2834 scr_LogPrint(LPRINT_NORMAL, "No such member: %s", nick);
2835 free_arg_lst(paramlst);
2836 g_free(nick);
2837 return;
2838 }
2839
2840 rst_time = buddy_getstatustime(bud, nick);
2841 rprio = buddy_getresourceprio(bud, nick);
2842 rst_msg = buddy_getstatusmsg(bud, nick);
2843 if (!rst_msg) rst_msg = "";
2844
2845 role = buddy_getrole(bud, nick);
2846 affil = buddy_getaffil(bud, nick);
2847 realjid = buddy_getrjid(bud, nick);
2848
2849 buffer = g_new(char, 4096);
2850
2851 snprintf(buffer, 4095, "Whois [%s]", nick);
2852 scr_WriteIncomingMessage(bjid, buffer, 0, msg_flag, 0);
2853 snprintf(buffer, 4095, "Status : [%c] %s", imstatus2char[rstatus],
2854 rst_msg);
2855 scr_WriteIncomingMessage(bjid, buffer, 0, msg_flag | HBB_PREFIX_CONT, 0);
2856
2857 if (rst_time) {
2858 char tbuf[128];
2859
2860 strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", localtime(&rst_time));
2861 snprintf(buffer, 127, "Timestamp: %s", tbuf);
2862 scr_WriteIncomingMessage(bjid, buffer, 0, msg_flag | HBB_PREFIX_CONT, 0);
2863 }
2864
2865 if (realjid) {
2866 snprintf(buffer, 4095, "JID : <%s>", realjid);
2867 scr_WriteIncomingMessage(bjid, buffer, 0, msg_flag | HBB_PREFIX_CONT, 0);
2868 }
2869
2870 snprintf(buffer, 4095, "Role : %s", strrole[role]);
2871 scr_WriteIncomingMessage(bjid, buffer, 0, msg_flag | HBB_PREFIX_CONT, 0);
2872 snprintf(buffer, 4095, "Affiliat.: %s", straffil[affil]);
2873 scr_WriteIncomingMessage(bjid, buffer, 0, msg_flag | HBB_PREFIX_CONT, 0);
2874 snprintf(buffer, 4095, "Priority : %d", rprio);
2875 scr_WriteIncomingMessage(bjid, buffer, 0, msg_flag | HBB_PREFIX_CONT, 0);
2876
2877 scr_WriteIncomingMessage(bjid, "End of WHOIS", 0, msg_flag, 0);
2878
2879 g_free(buffer);
2880 g_free(nick);
2881 free_arg_lst(paramlst);
2882 }
2883
2884 static void room_bookmark(gpointer bud, char *arg)
2885 {
2886 const char *roomid;
2887 const char *name = NULL, *nick = NULL;
2888 char *tmpnick = NULL;
2889 enum room_autowhois autowhois = 0;
2890 enum room_printstatus printstatus = 0;
2891 enum { bm_add = 0, bm_del = 1 } action = 0;
2892 int autojoin = 0;
2893 int nick_set = 0;
2894
2895 if (arg && *arg) {
2896 // /room bookmark [add|del] [[+|-]autojoin] [-|nick]
2897 char **paramlst;
2898 char **pp;
2899
2900 paramlst = split_arg(arg, 3, 0); // At most 3 parameters
2901 for (pp = paramlst; *pp; pp++) {
2902 if (!strcasecmp(*pp, "add"))
2903 action = bm_add;
2904 else if (!strcasecmp(*pp, "del"))
2905 action = bm_del;
2906 else if (!strcasecmp(*pp, "-autojoin"))
2907 autojoin = 0;
2908 else if (!strcasecmp(*pp, "+autojoin") || !strcasecmp(*pp, "autojoin"))
2909 autojoin = 1;
2910 else if (!strcmp(*pp, "-"))
2911 nick_set = 1;
2912 else {
2913 nick_set = 1;
2914 nick = tmpnick = to_utf8 (*pp);
2915 }
2916 }
2917 free_arg_lst(paramlst);
2918 }
2919
2920 roomid = buddy_getjid(bud);
2921
2922 if (action == bm_add) {
2923 name = buddy_getname(bud);
2924 if (!nick_set)
2925 nick = buddy_getnickname(bud);
2926 printstatus = buddy_getprintstatus(bud);
2927 autowhois = buddy_getautowhois(bud);
2928 }
2929
2930 xmpp_set_storage_bookmark(roomid, name, nick, NULL, autojoin,
2931 printstatus, autowhois);
2932 g_free (tmpnick);
2933 }
2934
2935 static void display_all_bookmarks(void)
2936 {
2937 GSList *bm, *bmp;
2938 GString *sbuf;
2939 struct bookmark *bm_elt;
2940
2941 bm = xmpp_get_all_storage_bookmarks();
2942
2943 if (!bm)
2944 return;
2945
2946 sbuf = g_string_new("");
2947
2948 scr_WriteIncomingMessage(NULL, "List of MUC bookmarks:",
2949 0, HBB_PREFIX_INFO, 0);
2950
2951 for (bmp = bm; bmp; bmp = g_slist_next(bmp)) {
2952 bm_elt = bmp->data;
2953 g_string_printf(sbuf, "%c <%s>",
2954 (bm_elt->autojoin ? '*' : ' '), bm_elt->roomjid);
2955 if (bm_elt->nick)
2956 g_string_append_printf(sbuf, " (%s)", bm_elt->nick);
2957 if (bm_elt->name)
2958 g_string_append_printf(sbuf, " %s", bm_elt->name);
2959 g_free(bm_elt->roomjid);
2960 g_free(bm_elt->name);
2961 g_free(bm_elt->nick);
2962 g_free(bm_elt);
2963 scr_WriteIncomingMessage(NULL, sbuf->str,
2964 0, HBB_PREFIX_INFO | HBB_PREFIX_CONT, 0);
2965 }
2966
2967 scr_setmsgflag_if_needed(SPECIAL_BUFFER_STATUS_ID, TRUE);
2968 update_roster = TRUE;
2969 g_string_free(sbuf, TRUE);
2970 g_slist_free(bm);
2971 }
2972
2973 #ifdef MODULES_ENABLE
2974 static gint module_list_comparator(gconstpointer arg1, gconstpointer arg2)
2975 {
2976 const loaded_module_t *module = arg1;
2977 const char *name = arg2;
2978 return g_strcmp0(module->name, name);
2979 }
2980
2981 static void do_load(char *arg)
2982 {
2983 GModule *mod;
2984 GSList *lmod;
2985 char *mdir, *path;
2986 if (!arg || !*arg) {
2987 scr_LogPrint(LPRINT_LOGNORM, "Missing modulename.");
2988 return;
2989 }
2990 lmod = g_slist_find_custom(loaded_modules, arg, module_list_comparator);
2991 if (lmod) {
2992 scr_LogPrint(LPRINT_LOGNORM, "Module %s is already loaded.", arg);
2993 return;
2994 }
2995 mdir = expand_filename(settings_opt_get("modules_dir"));
2996 path = g_module_build_path(mdir, arg);
2997 mod = g_module_open(path, G_MODULE_BIND_LAZY);
2998 if (!mod)
2999 scr_LogPrint(LPRINT_LOGNORM, "Module loading failed: %s",
3000 g_module_error());
3001 else {
3002 loaded_module_t *module = g_new(loaded_module_t, 1);
3003 module->name = g_strdup(arg);
3004 module->module = mod;
3005 loaded_modules = g_slist_prepend(loaded_modules, module);
3006 scr_LogPrint(LPRINT_LOGNORM, "Loaded module %s.", arg);
3007 }
3008 g_free(path);
3009 g_free(mdir);
3010 }
3011
3012 static void do_unload(char *arg)
3013 {
3014 GSList *module;
3015 if (!arg || !*arg) {
3016 scr_LogPrint(LPRINT_LOGNORM, "Missing modulename.");
3017 return;
3018 }
3019 module = g_slist_find_custom(loaded_modules, arg, module_list_comparator);
3020 if (module) {
3021 loaded_module_t *mod = module->data;
3022 if (!g_module_close(mod->module))
3023 scr_LogPrint(LPRINT_LOGNORM, "Module unloading failed: %s",
3024 g_module_error());
3025 else {
3026 g_free(mod->name);
3027 g_free(mod);
3028 loaded_modules = g_slist_delete_link(loaded_modules, module);
3029 scr_LogPrint(LPRINT_LOGNORM, "Unloaded module %s.", arg);
3030 }
3031 } else
3032 scr_LogPrint(LPRINT_LOGNORM, "Module %s not loaded.", arg);
3033 }
3034 #endif
3035
3036 static void do_room(char *arg)
3037 {
3038 char **paramlst;
3039 char *subcmd;
3040 gpointer bud;
3041
3042 if (!lm_connection_is_authenticated(lconnection)) {
3043 scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
3044 return;
3045 }
3046
3047 paramlst = split_arg(arg, 2, 1); // subcmd, arg
3048 subcmd = *paramlst;
3049 arg = *(paramlst+1);
3050
3051 if (!subcmd || !*subcmd) {
3052 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
3053 free_arg_lst(paramlst);
3054 return;
3055 }
3056
3057 if (current_buddy) {
3058 bud = BUDDATA(current_buddy);
3059 } else {
3060 if (strcasecmp(subcmd, "join")) {
3061 free_arg_lst(paramlst);
3062 return;
3063 }
3064 // "room join" is a special case, we don't need to have a valid
3065 // current_buddy.
3066 bud = NULL;
3067 }
3068
3069 if (!strcasecmp(subcmd, "join")) {
3070 if ((arg = check_room_subcommand(arg, FALSE, NULL)) != NULL)
3071 room_join(bud, arg);
3072 } else if (!strcasecmp(subcmd, "invite")) {
3073 if ((arg = check_room_subcommand(arg, TRUE, bud)) != NULL)
3074 room_invite(bud, arg);
3075 } else if (!strcasecmp(subcmd, "affil")) {
3076 if ((arg = check_room_subcommand(arg, TRUE, bud)) != NULL)
3077 room_affil(bud, arg);
3078 } else if (!strcasecmp(subcmd, "role")) {
3079 if ((arg = check_room_subcommand(arg, TRUE, bud)) != NULL)
3080 room_role(bud, arg);
3081 } else if (!strcasecmp(subcmd, "ban")) {
3082 if ((arg = check_room_subcommand(arg, TRUE, bud)) != NULL)
3083 room_ban(bud, arg);
3084 } else if (!strcasecmp(subcmd, "unban")) {
3085 if ((arg = check_room_subcommand(arg, TRUE, bud)) != NULL)
3086 room_unban(bud, arg);
3087 } else if (!strcasecmp(subcmd, "kick")) {
3088 if ((arg = check_room_subcommand(arg, TRUE, bud)) != NULL)
3089 room_kick(bud, arg);
3090 } else if (!strcasecmp(subcmd, "leave")) {
3091 if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
3092 cmd_room_leave(bud, arg);
3093 } else if (!strcasecmp(subcmd, "names")) {
3094 if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
3095 room_names(bud, arg);
3096 } else if (!strcasecmp(subcmd, "nick")) {
3097 if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
3098 room_nick(bud, arg);
3099 } else if (!strcasecmp(subcmd, "privmsg")) {
3100 if ((arg = check_room_subcommand(arg, TRUE, bud)) != NULL)
3101 room_privmsg(bud, arg);
3102 } else if (!strcasecmp(subcmd, "remove")) {
3103 if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
3104 room_remove(bud, arg);
3105 } else if (!strcasecmp(subcmd, "destroy")) {
3106 if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
3107 room_destroy(bud, arg);
3108 } else if (!strcasecmp(subcmd, "unlock")) {
3109 if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
3110 room_unlock(bud, arg);
3111 } else if (!strcasecmp(subcmd, "setopt")) {
3112 if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
3113 room_setopt(bud, arg);
3114 } else if (!strcasecmp(subcmd, "topic")) {
3115 if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
3116 room_topic(bud, arg);
3117 } else if (!strcasecmp(subcmd, "whois")) {
3118 if ((arg = check_room_subcommand(arg, TRUE, bud)) != NULL)
3119 cmd_room_whois(bud, arg, TRUE);
3120 } else if (!strcasecmp(subcmd, "bookmark")) {
3121 if (!arg && !buddy_getjid(BUDDATA(current_buddy)) &&
3122 buddy_gettype(BUDDATA(current_buddy)) == ROSTER_TYPE_SPECIAL)
3123 display_all_bookmarks();
3124 else if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
3125 room_bookmark(bud, arg);
3126 } else {
3127 scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
3128 }
3129
3130 free_arg_lst(paramlst);
3131 }
3132
3133 static void do_authorization(char *arg)
3134 {
3135 char **paramlst;
3136 char *subcmd;
3137 char *jid_utf8;
3138
3139 if (!lm_connection_is_authenticated(lconnection)) {
3140 scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
3141 return;
3142 }
3143
3144 paramlst = split_arg(arg, 2, 0); // subcmd, [jid]
3145 subcmd = *paramlst;
3146 arg = *(paramlst+1);
3147
3148 if (!subcmd || !*subcmd) {
3149 scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
3150 goto do_authorization_return;
3151 }
3152
3153 // Use the provided jid, if it looks valid
3154 if (arg) {
3155 if (!*arg) {
3156 // If no jid is provided, we use the current selected buddy
3157 arg = NULL;
3158 } else {
3159 if (check_jid_syntax(arg)) {
3160 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
3161 "<%s> is not a valid Jabber ID.", arg);
3162 goto do_authorization_return;
3163 }
3164 }
3165 }
3166
3167 if (!arg) { // Use the current selected buddy's jid
3168 gpointer bud;
3169 guint type;
3170
3171 if (!current_buddy)
3172 goto do_authorization_return;
3173 bud = BUDDATA(current_buddy);
3174
3175 jid_utf8 = arg = (char*)buddy_getjid(bud);
3176 type = buddy_gettype(bud);
3177
3178 if (!(type & (ROSTER_TYPE_USER|ROSTER_TYPE_AGENT))) {
3179 scr_LogPrint(LPRINT_NORMAL, "Invalid buddy.");
3180 goto do_authorization_return;
3181 }
3182 } else {
3183 jid_utf8 = to_utf8(arg);
3184 }
3185
3186 if (!strcasecmp(subcmd, "allow")) {
3187 xmpp_send_s10n(jid_utf8, LM_MESSAGE_SUB_TYPE_SUBSCRIBED);
3188 scr_LogPrint(LPRINT_LOGNORM,
3189 "Sent presence subscription approval to <%s>.",
3190 jid_utf8);
3191 } else if (!strcasecmp(subcmd, "cancel")) {
3192 xmpp_send_s10n(jid_utf8, LM_MESSAGE_SUB_TYPE_UNSUBSCRIBED);
3193 scr_LogPrint(LPRINT_LOGNORM,
3194 "<%s> will no longer receive your presence updates.",
3195 jid_utf8);
3196 } else if (!strcasecmp(subcmd, "request")) {
3197 xmpp_send_s10n(jid_utf8, LM_MESSAGE_SUB_TYPE_SUBSCRIBE);
3198 scr_LogPrint(LPRINT_LOGNORM,
3199 "Sent presence notification request to <%s>.", jid_utf8);
3200 } else if (!strcasecmp(subcmd, "request_unsubscribe")) {
3201 xmpp_send_s10n(jid_utf8, LM_MESSAGE_SUB_TYPE_UNSUBSCRIBE);
3202 scr_LogPrint(LPRINT_LOGNORM,
3203 "Sent presence notification unsubscription request to <%s>.",
3204 jid_utf8);
3205 } else {
3206 scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
3207 }
3208
3209 // Only free jid_utf8 if it has been allocated, i.e. if != arg.
3210 if (jid_utf8 && jid_utf8 != arg)
3211 g_free(jid_utf8);
3212 do_authorization_return:
3213 free_arg_lst(paramlst);
3214 }
3215
3216 static void do_version(char *arg)
3217 {
3218 gchar *ver = mcabber_version();
3219 scr_LogPrint(LPRINT_NORMAL, "This is mcabber version %s.", ver);
3220 g_free(ver);
3221 }
3222
3223 static void do_request(char *arg)
3224 {
3225 char **paramlst;
3226 char *fjid, *type;
3227 enum iqreq_type numtype = iqreq_none;
3228 char *jid_utf8 = NULL;
3229
3230 paramlst = split_arg(arg, 2, 0); // type, jid
3231 type = *paramlst;
3232 fjid = *(paramlst+1);
3233
3234 if (type) {
3235 // Quick check...
3236 if (!strcasecmp(type, "version"))
3237 numtype = iqreq_version;
3238 else if (!strcasecmp(type, "time"))
3239 numtype = iqreq_time;
3240 else if (!strcasecmp(type, "last"))
3241 numtype = iqreq_last;
3242 else if (!strcasecmp(type, "vcard"))
3243 numtype = iqreq_vcard;
3244 }
3245
3246 if (!type || !numtype) {
3247 scr_LogPrint(LPRINT_NORMAL,
3248 "Please specify a query type (version, time...).");
3249 free_arg_lst(paramlst);
3250 return;
3251 }
3252
3253 if (!lm_connection_is_authenticated(lconnection)) {
3254 scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
3255 free_arg_lst(paramlst);
3256 return;
3257 }
3258
3259 // Allow special jid "" or "." (current buddy)
3260 if (fjid && (!*fjid || !strcmp(fjid, ".")))
3261 fjid = NULL;
3262
3263 if (fjid) {
3264 // The JID has been specified. Quick check...
3265 if (check_jid_syntax(fjid)) {
3266 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
3267 "<%s> is not a valid Jabber ID.", fjid);
3268 fjid = NULL;
3269 } else {
3270 // Convert jid to lowercase
3271 char *p;
3272 for (p = fjid; *p && *p != JID_RESOURCE_SEPARATOR; p++)
3273 *p = tolower(*p);
3274 fjid = jid_utf8 = to_utf8(fjid);
3275 }
3276 } else {
3277 // Add the current buddy
3278 if (current_buddy)
3279 fjid = (char*)buddy_getjid(BUDDATA(current_buddy));
3280 if (!fjid)
3281 scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
3282 }
3283
3284 if (fjid) {
3285 switch (numtype) {
3286 case iqreq_version:
3287 case iqreq_time:
3288 case iqreq_last:
3289 case iqreq_vcard:
3290 xmpp_request(fjid, numtype);
3291 break;
3292 default:
3293 break;
3294 }
3295 }
3296 g_free(jid_utf8);
3297 free_arg_lst(paramlst);
3298 }
3299
3300 static void do_event(char *arg)
3301 {
3302 char **paramlst;
3303 char *evid, *subcmd;
3304 int action = -1;
3305 GSList *evidlst;
3306
3307 paramlst = split_arg(arg, 2, 0); // id, subcmd
3308 evid = *paramlst;
3309 subcmd = *(paramlst+1);
3310
3311 if (!evid || !subcmd) {
3312 // Special case: /event list
3313 if (evid && !strcasecmp(evid, "list"))
3314 evs_display_list();
3315 else
3316 scr_LogPrint(LPRINT_NORMAL,
3317 "Missing parameter. Usage: /event num action");
3318 free_arg_lst(paramlst);
3319 return;
3320 }
3321
3322 if (!strcasecmp(subcmd, "reject"))
3323 action = 0;
3324 else if (!strcasecmp(subcmd, "accept"))
3325 action = 1;
3326 else if (!strcasecmp(subcmd, "ignore"))
3327 action = 2;
3328
3329 if (action == -1) {
3330 scr_LogPrint(LPRINT_NORMAL, "Wrong action parameter.");
3331 } else if (action >= 0 && action <= 2) {
3332 GSList *p;
3333
3334 if (action == 2) {
3335 action = EVS_CONTEXT_CANCEL;
3336 } else {
3337 action += EVS_CONTEXT_USER;
3338 }
3339
3340 if (!strcmp(evid, "*")) {
3341 // Use completion list
3342 evidlst = evs_geteventslist(FALSE);
3343 } else {
3344 // Let's create a slist with the provided event id
3345 evidlst = g_slist_append(NULL, g_strdup(evid));
3346 }
3347 for (p = evidlst; p; p = g_slist_next(p)) {
3348 if (evs_callback(p->data, action) == -1) {
3349 scr_LogPrint(LPRINT_NORMAL, "Event %s not found.", p->data);
3350 }
3351 g_free(p->data);
3352 }
3353 g_slist_free(evidlst);
3354 }
3355
3356 free_arg_lst(paramlst);
3357 }
3358
3359 static void do_pgp(char *arg)
3360 {
3361 char **paramlst;
3362 char *fjid, *subcmd, *keyid;
3363 enum {
3364 pgp_none,
3365 pgp_enable,
3366 pgp_disable,
3367 pgp_setkey,
3368 pgp_force,
3369 pgp_info
3370 } op = 0;
3371 int force = FALSE;
3372
3373 paramlst = split_arg(arg, 3, 0); // subcmd, jid, [key]
3374 subcmd = *paramlst;
3375 fjid = *(paramlst+1);
3376 keyid = *(paramlst+2);
3377
3378 if (!subcmd)
3379 fjid = NULL;
3380 if (!fjid)
3381 keyid = NULL;
3382
3383 if (subcmd) {
3384 if (!strcasecmp(subcmd, "enable"))
3385 op = pgp_enable;
3386 else if (!strcasecmp(subcmd, "disable"))
3387 op = pgp_disable;
3388 else if (!strcasecmp(subcmd, "setkey"))
3389 op = pgp_setkey;
3390 else if ((!strcasecmp(subcmd, "force")) ||
3391 (!strcasecmp(subcmd, "+force"))) {
3392 op = pgp_force;
3393 force = TRUE;
3394 } else if (!strcasecmp(subcmd, "-force"))
3395 op = pgp_force;
3396 else if (!strcasecmp(subcmd, "info"))
3397 op = pgp_info;
3398 }
3399
3400 if (!op) {
3401 scr_LogPrint(LPRINT_NORMAL, "Unrecognized or missing parameter!");
3402 free_arg_lst(paramlst);
3403 return;
3404 }
3405
3406 // Allow special jid "" or "." (current buddy)
3407 if (fjid && (!*fjid || !strcmp(fjid, ".")))
3408 fjid = NULL;
3409
3410 if (fjid) {
3411 // The JID has been specified. Quick check...
3412 if (check_jid_syntax(fjid) || !strchr(fjid, '@')) {
3413 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
3414 "<%s> is not a valid Jabber ID.", fjid);
3415 fjid = NULL;
3416 } else {
3417 // Convert jid to lowercase and strip resource
3418 char *p;
3419 for (p = fjid; *p && *p != JID_RESOURCE_SEPARATOR; p++)
3420 *p = tolower(*p);
3421 if (*p == JID_RESOURCE_SEPARATOR)
3422 *p = '\0';
3423 }
3424 } else {
3425 gpointer bud = NULL;
3426 if (current_buddy)
3427 bud = BUDDATA(current_buddy);
3428 if (bud) {
3429 guint type = buddy_gettype(bud);
3430 if (type & ROSTER_TYPE_USER) // Is it a user?
3431 fjid = (char*)buddy_getjid(bud);
3432 else
3433 scr_LogPrint(LPRINT_NORMAL, "The selected item should be a user.");
3434 }
3435 }
3436
3437 if (fjid) { // fjid is actually a bare jid...
3438 guint disabled;
3439 GString *sbuf;
3440 switch (op) {
3441 case pgp_enable:
3442 case pgp_disable:
3443 settings_pgp_setdisabled(fjid, (op == pgp_disable ? TRUE : FALSE));
3444 break;
3445 case pgp_force:
3446 settings_pgp_setforce(fjid, force);
3447 break;
3448 case pgp_setkey:
3449 settings_pgp_setkeyid(fjid, keyid);
3450 break;
3451 case pgp_info:
3452 sbuf = g_string_new("");
3453 if (settings_pgp_getkeyid(fjid)) {
3454 g_string_printf(sbuf, "PGP Encryption key id: %s",
3455 settings_pgp_getkeyid(fjid));
3456 scr_WriteIncomingMessage(fjid, sbuf->str, 0, HBB_PREFIX_INFO, 0);
3457 }
3458 disabled = settings_pgp_getdisabled(fjid);
3459 g_string_printf(sbuf, "PGP encryption is %s",
3460 (disabled ? "disabled" : "enabled"));
3461 scr_WriteIncomingMessage(fjid, sbuf->str, 0, HBB_PREFIX_INFO, 0);
3462 if (!disabled && settings_pgp_getforce(fjid)) {
3463 scr_WriteIncomingMessage(fjid,
3464 "Encryption enforced (no negotiation)",
3465 0, HBB_PREFIX_INFO, 0);
3466 }
3467 g_string_free(sbuf, TRUE);
3468 break;
3469 default:
3470 break;
3471 }
3472 } else {
3473 scr_LogPrint(LPRINT_NORMAL, "Please specify a valid Jabber ID.");
3474 }
3475
3476 free_arg_lst(paramlst);
3477 }
3478
3479 static void do_otr(char *arg)
3480 {
3481 #ifdef HAVE_LIBOTR
3482 char **paramlst;
3483 char *fjid, *subcmd, *keyid;
3484 enum {
3485 otr_none,
3486 otr_start,
3487 otr_stop,
3488 otr_fpr,
3489 otr_smpq,
3490 otr_smpr,
3491 otr_smpa,
3492 otr_k,
3493 otr_info
3494 } op = 0;
3495
3496 if (!otr_enabled()) {
3497 scr_LogPrint(LPRINT_LOGNORM,
3498 "Warning: OTR hasn't been enabled -- command ignored.");
3499 return;
3500 }
3501
3502 paramlst = split_arg(arg, 3, 0); // subcmd, jid, [key]
3503 subcmd = *paramlst;
3504 fjid = *(paramlst+1);
3505 keyid = *(paramlst+2);
3506
3507 if (!subcmd)
3508 fjid = NULL;
3509 if (!fjid)
3510 keyid = NULL;
3511
3512 if (subcmd) {
3513 if (!strcasecmp(subcmd, "start"))
3514 op = otr_start;
3515 else if (!strcasecmp(subcmd, "stop"))
3516 op = otr_stop;
3517 else if (!strcasecmp(subcmd, "fingerprint"))
3518 op = otr_fpr;
3519 else if (!strcasecmp(subcmd, "smpq"))
3520 op = otr_smpq;
3521 else if (!strcasecmp(subcmd, "smpr"))
3522 op = otr_smpr;
3523 else if (!strcasecmp(subcmd, "smpa"))
3524 op = otr_smpa;
3525 else if (!strcasecmp(subcmd, "key"))
3526 op = otr_k;
3527 else if (!strcasecmp(subcmd, "info"))
3528 op = otr_info;
3529 }
3530
3531 if (!op) {
3532 scr_LogPrint(LPRINT_NORMAL, "Unrecognized or missing parameter!");
3533 free_arg_lst(paramlst);
3534 return;
3535 }
3536
3537 if (op == otr_k)
3538 otr_key();
3539 else {
3540 // Allow special jid "" or "." (current buddy)
3541 if (fjid && (!*fjid || !strcmp(fjid, ".")))
3542 fjid = NULL;
3543
3544 if (fjid) {
3545 // The JID has been specified. Quick check...
3546 if (check_jid_syntax(fjid) || !strchr(fjid, '@')) {
3547 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
3548 "<%s> is not a valid Jabber ID.", fjid);
3549 fjid = NULL;
3550 } else {
3551 // Convert jid to lowercase and strip resource
3552 char *p;
3553 for (p = fjid; *p && *p != JID_RESOURCE_SEPARATOR; p++)
3554 *p = tolower(*p);
3555 if (*p == JID_RESOURCE_SEPARATOR)
3556 *p = '\0';
3557 }
3558 } else {
3559 gpointer bud = NULL;
3560 if (current_buddy)
3561 bud = BUDDATA(current_buddy);
3562 if (bud) {
3563 guint type = buddy_gettype(bud);
3564 if (type & ROSTER_TYPE_USER) // Is it a user?
3565 fjid = (char*)buddy_getjid(bud);
3566 else
3567 scr_LogPrint(LPRINT_NORMAL, "The selected item should be a user.");
3568 }
3569 }
3570
3571 if (fjid) { // fjid is actually a bare jid...
3572 switch (op) {
3573 case otr_start:
3574 otr_establish(fjid); break;
3575 case otr_stop:
3576 otr_disconnect(fjid); break;
3577 case otr_fpr:
3578 otr_fingerprint(fjid, keyid); break;
3579 case otr_smpq:
3580 otr_smp_query(fjid, keyid); break;
3581 case otr_smpr:
3582 otr_smp_respond(fjid, keyid); break;
3583 case otr_smpa:
3584 otr_smp_abort(fjid); break;
3585 case otr_info:
3586 otr_print_info(fjid); break;
3587 default:
3588 break;
3589 }
3590 } else
3591 scr_LogPrint(LPRINT_NORMAL, "Please specify a valid Jabber ID.");
3592 }
3593 free_arg_lst(paramlst);
3594
3595 #else
3596 scr_LogPrint(LPRINT_NORMAL, "Please recompile mcabber with libotr enabled.");
3597 #endif /* HAVE_LIBOTR */
3598 }
3599
3600 #ifdef HAVE_LIBOTR
3601 static char *string_for_otrpolicy(enum otr_policy p)
3602 {
3603 switch (p) {
3604 case plain: return "plain";
3605 case opportunistic: return "opportunistic";
3606 case manual: return "manual";
3607 case always: return "always";
3608 default: return "unknown";
3609 }
3610 }
3611
3612 static void dump_otrpolicy(char *k, char *v, void *nothing)
3613 {
3614 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8, "otrpolicy for %s: %s", k,
3615 string_for_otrpolicy(*(enum otr_policy*)v));
3616 }
3617 #endif
3618
3619 static void do_otrpolicy(char *arg)
3620 {
3621 #ifdef HAVE_LIBOTR
3622 char **paramlst;
3623 char *fjid, *policy;
3624 enum otr_policy p;
3625
3626 paramlst = split_arg(arg, 2, 0); // [jid|default] policy
3627 fjid = *paramlst;
3628 policy = *(paramlst+1);
3629
3630 if (!fjid && !policy) {
3631 scr_LogPrint(LPRINT_NORMAL, "default otrpolicy: %s",
3632 string_for_otrpolicy(settings_otr_getpolicy(NULL)));
3633 settings_foreach(SETTINGS_TYPE_OTR, &dump_otrpolicy, NULL);
3634 free_arg_lst(paramlst);
3635 return;
3636 }
3637
3638 if (!policy) {
3639 scr_LogPrint(LPRINT_NORMAL,
3640 "Please call otrpolicy correctly: /otrpolicy (default|jid) "
3641 "(plain|manual|opportunistic|always)");
3642 free_arg_lst(paramlst);
3643 return;
3644 }
3645
3646 if (!strcasecmp(policy, "plain"))
3647 p = plain;
3648 else if (!strcasecmp(policy, "manual"))
3649 p = manual;
3650 else if (!strcasecmp(policy, "opportunistic"))
3651 p = opportunistic;
3652 else if (!strcasecmp(policy, "always"))
3653 p = always;
3654 else {
3655 /* Fail, we don't know _this_ policy*/
3656 scr_LogPrint(LPRINT_NORMAL, "mcabber doesn't support _this_ policy!");
3657 free_arg_lst(paramlst);
3658 return;
3659 }
3660
3661 if (!strcasecmp(fjid, "default") || !strcasecmp(fjid, "*")) {
3662 /*set default policy*/
3663 settings_otr_setpolicy(NULL, p);
3664 free_arg_lst(paramlst);
3665 return;
3666 }
3667 // Allow special jid "" or "." (current buddy)
3668 if (fjid && (!*fjid || !strcmp(fjid, ".")))
3669 fjid = NULL;
3670
3671 if (fjid) {
3672 // The JID has been specified. Quick check...
3673 if (check_jid_syntax(fjid) || !strchr(fjid, '@')) {
3674 scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
3675 "<%s> is not a valid Jabber ID.", fjid);
3676 fjid = NULL;
3677 } else {
3678 // Convert jid to lowercase and strip resource
3679 char *p;
3680 for (p = fjid; *p && *p != JID_RESOURCE_SEPARATOR; p++)
3681 *p = tolower(*p);
3682 if (*p == JID_RESOURCE_SEPARATOR)
3683 *p = '\0';
3684 }
3685 } else {
3686 gpointer bud = NULL;
3687 if (current_buddy)
3688 bud = BUDDATA(current_buddy);
3689 if (bud) {
3690 guint type = buddy_gettype(bud);
3691 if (type & ROSTER_TYPE_USER) // Is it a user?
3692 fjid = (char*)buddy_getjid(bud);
3693 else
3694 scr_LogPrint(LPRINT_NORMAL, "The selected item should be a user.");
3695 }
3696 }
3697
3698 if (fjid)
3699 settings_otr_setpolicy(fjid, p);
3700 else
3701 scr_LogPrint(LPRINT_NORMAL, "Please specify a valid Jabber ID.");
3702
3703 free_arg_lst(paramlst);
3704 #else
3705 scr_LogPrint(LPRINT_NORMAL, "Please recompile mcabber with libotr enabled.");
3706 #endif /* HAVE_LIBOTR */
3707 }
3708
3709 /* !!!
3710 After changing the /iline arguments names here, you must change ones
3711 in init_bindings().
3712 */
3713 static void do_iline(char *arg)
3714 {
3715 if (!strcasecmp(arg, "fword")) {
3716 readline_forward_word();
3717 } else if (!strcasecmp(arg, "bword")) {
3718 readline_backward_word();
3719 } else if (!strcasecmp(arg, "word_fdel")) {
3720 readline_forward_kill_word();
3721 } else if (!strcasecmp(arg, "word_bdel")) {
3722 readline_backward_kill_word();
3723 } else if (!strcasecmp(arg, "word_upcase")) {
3724 readline_updowncase_word(1);
3725 } else if (!strcasecmp(arg, "word_downcase")) {
3726 readline_updowncase_word(0);
3727 } else if (!strcasecmp(arg, "word_capit")) {
3728 readline_capitalize_word();
3729 } else if (!strcasecmp(arg, "fchar")) {
3730 readline_forward_char();
3731 } else if (!strcasecmp(arg, "bchar")) {
3732 readline_backward_char();
3733 } else if (!strcasecmp(arg, "char_fdel")) {
3734 readline_forward_kill_char();
3735 } else if (!strcasecmp(arg, "char_bdel")) {
3736 readline_backward_kill_char();
3737 } else if (!strcasecmp(arg, "char_swap")) {
3738 readline_transpose_chars();
3739 } else if (!strcasecmp(arg, "hist_beginning_search_bwd")) {
3740 readline_hist_beginning_search_bwd();
3741 } else if (!strcasecmp(arg, "hist_beginning_search_fwd")) {
3742 readline_hist_beginning_search_fwd();
3743 } else if (!strcasecmp(arg, "hist_prev")) {
3744 readline_hist_prev();
3745 } else if (!strcasecmp(arg, "hist_next")) {
3746 readline_hist_next();
3747 } else if (!strcasecmp(arg, "iline_start")) {
3748 readline_iline_start();
3749 } else if (!strcasecmp(arg, "iline_end")) {
3750 readline_iline_end();
3751 } else if (!strcasecmp(arg, "iline_fdel")) {
3752 readline_forward_kill_iline();
3753 } else if (!strcasecmp(arg, "iline_bdel")) {
3754 readline_backward_kill_iline();
3755 } else if (!strcasecmp(arg, "send_multiline")) {
3756 readline_send_multiline();
3757 } else if (!strcasecmp(arg, "iline_accept")) {
3758 retval_for_cmds = readline_accept_line(FALSE);
3759 } else if (!strcasecmp(arg, "iline_accept_down_hist")) {
3760 retval_for_cmds = readline_accept_line(TRUE);
3761 } else if (!strcasecmp(arg, "compl_cancel")) {
3762 readline_cancel_completion();
3763 } else if (!strcasecmp(arg, "compl_do")) {
3764 readline_do_completion();
3765 }
3766 }
3767
3768 static void do_screen_refresh(char *arg)
3769 {
3770 readline_refresh_screen();
3771 }
3772
3773 static void do_chat_disable(char *arg)
3774 {
3775 guint show_roster;
3776
3777 if (arg && !strcasecmp(arg, "--show-roster"))
3778 show_roster = 1;
3779 else
3780 show_roster = 0;
3781
3782 readline_disable_chat_mode(show_roster);
3783 }
3784
3785 static void do_source(char *arg)
3786 {
3787 static int recur_level;
3788 gchar *filename, *expfname;
3789 if (!*arg) {
3790 scr_LogPrint(LPRINT_NORMAL, "Missing filename.");
3791 return;
3792 }
3793 if (recur_level > 20) {
3794 scr_LogPrint(LPRINT_LOGNORM, "** Too many source commands!");
3795 return;
3796 }
3797 filename = g_strdup(arg);
3798 strip_arg_special_chars(filename);
3799 expfname = expand_filename(filename);
3800 recur_level++;
3801 cfg_read_file(expfname, FALSE);
3802 recur_level--;
3803 g_free(filename);
3804 g_free(expfname);
3805 }
3806
3807 static void do_connect(char *arg)
3808 {
3809 xmpp_connect();
3810 }
3811
3812 static void do_disconnect(char *arg)
3813 {
3814 xmpp_disconnect();
3815 }
3816
3817 static void do_help(char *arg)
3818 {
3819 help_process(arg);
3820 }
3821
3822 static void do_echo(char *arg)
3823 {
3824 if (arg)
3825 scr_print_logwindow(arg);
3826 }
3827
3828 /* vim: set expandtab cindent cinoptions=>2\:2(0: For Vim users... */