6 * Copyright (C) 2003, Ethan Blanton <eblanton@cs.purdue.edu>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 #include "conversation.h"
33 static void irc_do_mode(struct irc_conn
*irc
, const char *target
, const char *sign
, char **ops
);
35 int irc_cmd_default(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
37 PurpleConversation
*convo
= purple_conversations_find_with_account(target
, irc
->account
);
43 buf
= g_strdup_printf(_("Unknown command: %s"), cmd
);
44 purple_conversation_write_system_message(convo
, buf
, PURPLE_MESSAGE_NO_LOG
);
50 int irc_cmd_away(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
54 if (args
[0] && strcmp(cmd
, "back")) {
55 message
= purple_markup_strip_html(args
[0]);
56 purple_util_chrreplace(message
, '\n', ' ');
57 buf
= irc_format(irc
, "v:", "AWAY", message
);
60 buf
= irc_format(irc
, "v", "AWAY");
68 int irc_cmd_ctcp(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
70 /* we have defined args as args[0] is target and args[1] is ctcp command */
74 /* check if we have args */
75 if (!args
|| !args
[0] || !args
[1])
78 /* TODO:strip newlines or send each line as separate ctcp or something
79 * actually, this shouldn't be done here but somewhere else since irc should support escaping newlines */
81 string
= g_string_new(args
[1]);
82 g_string_prepend_c (string
,'\001');
83 g_string_append_c (string
,'\001');
84 buf
= irc_format(irc
, "vn:", "PRIVMSG", args
[0], string
->str
);
85 g_string_free(string
,TRUE
);
93 int irc_cmd_ctcp_action(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
95 PurpleConnection
*gc
= purple_account_get_connection(irc
->account
);
96 char *action
, *escaped
, *dst
, **newargs
;
99 PurpleConversation
*convo
;
102 if (!args
|| !args
[0] || !gc
)
105 convo
= purple_conversations_find_with_account(target
, irc
->account
);
107 msg
= g_strdup_printf("/me %s", args
[0]);
109 /* XXX: we'd prefer to keep this in conversation.c */
110 if (PURPLE_IS_IM_CONVERSATION(convo
)) {
111 pmsg
= purple_message_new_outgoing(
112 purple_conversation_get_name(convo
), msg
, 0);
114 purple_signal_emit(purple_conversations_get_handle(),
115 "sending-im-msg", irc
->account
, pmsg
);
117 pmsg
= purple_message_new_outgoing(NULL
, msg
, 0);
119 purple_signal_emit(purple_conversations_get_handle(),
120 "sending-chat-msg", irc
->account
, pmsg
,
121 purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(convo
)));
125 if (purple_message_is_empty(pmsg
))
127 msg
= g_strdup(purple_message_get_contents(pmsg
)); /* XXX: is it really necessary? */
129 if (strncmp(msg
, "/me ", 4) != 0) {
130 newargs
= g_new0(char *, 2);
131 newargs
[0] = g_strdup(target
);
134 irc_cmd_privmsg(irc
, cmd
, target
, (const char **)newargs
);
139 action
= g_malloc(strlen(&msg
[4]) + 10);
141 sprintf(action
, "\001ACTION ");
147 if (*(src
+ 1) == '\0') {
160 newargs
= g_new0(char *, 2);
161 newargs
[0] = g_strdup(target
);
163 irc_cmd_privmsg(irc
, cmd
, target
, (const char **)newargs
);
169 /* XXX: we'd prefer to keep this in conversation.c */
170 if (PURPLE_IS_IM_CONVERSATION(convo
)) {
171 purple_signal_emit(purple_conversations_get_handle(),
172 "sent-im-msg", irc
->account
, pmsg
);
174 purple_signal_emit(purple_conversations_get_handle(),
175 "sent-chat-msg", irc
->account
, pmsg
,
176 purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(convo
)));
182 escaped
= g_markup_escape_text(args
[0], -1);
183 action
= g_strdup_printf("/me %s", escaped
);
185 if (action
[strlen(action
) - 1] == '\n')
186 action
[strlen(action
) - 1] = '\0';
187 if (PURPLE_IS_CHAT_CONVERSATION(convo
))
188 purple_serv_got_chat_in(gc
, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(convo
)),
189 purple_connection_get_display_name(gc
),
190 PURPLE_MESSAGE_SEND
, action
, time(NULL
));
192 purple_conversation_write_message(convo
, purple_message_new_outgoing(
193 purple_connection_get_display_name(gc
), action
, 0));
200 int irc_cmd_ctcp_version(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
204 if (!args
|| !args
[0])
207 buf
= irc_format(irc
, "vn:", "PRIVMSG", args
[0], "\001VERSION\001");
214 int irc_cmd_invite(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
218 if (!args
|| !args
[0] || !(args
[1] || target
))
221 buf
= irc_format(irc
, "vnc", "INVITE", args
[0], args
[1] ? args
[1] : target
);
228 int irc_cmd_join(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
232 if (!args
|| !args
[0])
236 buf
= irc_format(irc
, "vcv", "JOIN", args
[0], args
[1]);
238 buf
= irc_format(irc
, "vc", "JOIN", args
[0]);
245 int irc_cmd_kick(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
249 if (!args
|| !args
[0])
252 if (!purple_conversations_find_chat_with_account(target
, irc
->account
))
256 buf
= irc_format(irc
, "vcn:", "KICK", target
, args
[0], args
[1]);
258 buf
= irc_format(irc
, "vcn", "KICK", target
, args
[0]);
265 int irc_cmd_list(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
267 purple_roomlist_show_with_account(irc
->account
);
272 int irc_cmd_mode(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
274 PurpleConnection
*gc
;
280 if (!strcmp(cmd
, "mode")) {
281 if (!args
[0] && irc_ischannel(target
))
282 buf
= irc_format(irc
, "vc", "MODE", target
);
283 else if (args
[0] && (*args
[0] == '+' || *args
[0] == '-'))
284 buf
= irc_format(irc
, "vcn", "MODE", target
, args
[0]);
286 buf
= irc_format(irc
, "vn", "MODE", args
[0]);
289 } else if (!strcmp(cmd
, "umode")) {
292 gc
= purple_account_get_connection(irc
->account
);
293 buf
= irc_format(irc
, "vnc", "MODE", purple_connection_get_display_name(gc
), args
[0]);
304 int irc_cmd_names(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
308 if (!args
|| (!args
[0] && !irc_ischannel(target
)))
311 buf
= irc_format(irc
, "vc", "NAMES", args
[0] ? args
[0] : target
);
318 int irc_cmd_nick(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
322 if (!args
|| !args
[0])
325 buf
= irc_format(irc
, "v:", "NICK", args
[0]);
326 g_free(irc
->reqnick
);
327 irc
->reqnick
= g_strdup(args
[0]);
328 irc
->nickused
= FALSE
;
335 int irc_cmd_op(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
337 char **nicks
, **ops
, *sign
, *mode
;
340 if (!args
|| !args
[0] || !*args
[0])
343 if (!strcmp(cmd
, "op")) {
346 } else if (!strcmp(cmd
, "deop")) {
349 } else if (!strcmp(cmd
, "voice")) {
352 } else if (!strcmp(cmd
, "devoice")) {
356 purple_debug(PURPLE_DEBUG_ERROR
, "irc", "invalid 'op' command '%s'\n", cmd
);
360 nicks
= g_strsplit(args
[0], " ", -1);
362 for (i
= 0; nicks
[i
]; i
++)
364 ops
= g_new0(char *, i
* 2 + 1);
366 for (i
= 0; nicks
[i
]; i
++) {
369 ops
[used
++] = nicks
[i
];
373 irc_do_mode(irc
, target
, sign
, ops
);
380 int irc_cmd_part(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
388 buf
= irc_format(irc
, "vc:", "PART", args
[0] ? args
[0] : target
, args
[1]);
390 buf
= irc_format(irc
, "vc", "PART", args
[0] ? args
[0] : target
);
397 int irc_cmd_ping(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
402 if (args
&& args
[0]) {
403 if (irc_ischannel(args
[0]))
405 stamp
= g_strdup_printf("\001PING %lu\001", time(NULL
));
406 buf
= irc_format(irc
, "vn:", "PRIVMSG", args
[0], stamp
);
409 stamp
= g_strdup_printf("%s %lu", target
, time(NULL
));
410 buf
= irc_format(irc
, "v:", "PING", stamp
);
413 stamp
= g_strdup_printf("%lu", time(NULL
));
414 buf
= irc_format(irc
, "vv", "PING", stamp
);
423 int irc_cmd_privmsg(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
425 int max_privmsg_arg_len
;
426 const char *cur
, *end
;
430 if (!args
|| !args
[0] || !args
[1])
433 max_privmsg_arg_len
= IRC_MAX_MSG_SIZE
- strlen(args
[0]) - 64;
434 salvaged
= purple_utf8_salvage(args
[1]);
437 while (*end
&& *cur
) {
438 end
= strchr(cur
, '\n');
440 end
= cur
+ strlen(cur
);
441 if (end
- cur
> max_privmsg_arg_len
) {
442 /* this call is used to find the last valid character position in the first
443 * max_privmsg_arg_len bytes of the utf-8 message
445 g_utf8_validate(cur
, max_privmsg_arg_len
, &end
);
448 msg
= g_strndup(cur
, end
- cur
);
450 if(!strcmp(cmd
, "notice"))
451 buf
= irc_format(irc
, "vt:", "NOTICE", args
[0], msg
);
453 buf
= irc_format(irc
, "vt:", "PRIVMSG", args
[0], msg
);
469 int irc_cmd_quit(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
473 if (!irc
->quitting
) {
475 * Use purple_account_get_string(irc->account, "quitmsg", IRC_DEFAULT_QUIT)
476 * and uncomment the appropriate account preference in irc.c if we
477 * decide we want custom quit messages.
479 buf
= irc_format(irc
, "v:", "QUIT", (args
&& args
[0]) ? args
[0] : IRC_DEFAULT_QUIT
);
483 irc
->quitting
= TRUE
;
485 if (!purple_account_is_disconnecting(irc
->account
))
486 purple_account_set_status(irc
->account
, "offline", TRUE
, NULL
);
492 int irc_cmd_quote(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
496 if (!args
|| !args
[0])
499 buf
= irc_format(irc
, "n", args
[0]);
506 int irc_cmd_query(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
508 PurpleIMConversation
*im
;
509 PurpleConnection
*gc
;
511 if (!args
|| !args
[0])
514 im
= purple_im_conversation_new(irc
->account
, args
[0]);
515 purple_conversation_present(PURPLE_CONVERSATION(im
));
518 gc
= purple_account_get_connection(irc
->account
);
519 irc_cmd_privmsg(irc
, cmd
, target
, args
);
520 purple_conversation_write_message(PURPLE_CONVERSATION(im
),
521 purple_message_new_outgoing(
522 purple_connection_get_display_name(gc
), args
[1], 0));
528 int irc_cmd_remove(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
532 if (!args
|| !args
[0])
535 if (!irc_ischannel(target
)) /* not a channel, punt */
539 buf
= irc_format(irc
, "vcn:", "REMOVE", target
, args
[0], args
[1]);
541 buf
= irc_format(irc
, "vcn", "REMOVE", target
, args
[0]);
548 int irc_cmd_service(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
550 char *capital_cmd
, *buf
;
552 if (!args
|| !args
[0])
555 /* cmd will be one of nickserv, chanserv, memoserv or operserv */
556 capital_cmd
= g_ascii_strup(cmd
, -1);
557 buf
= irc_format(irc
, "v:", capital_cmd
, args
[0]);
565 int irc_cmd_time(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
569 buf
= irc_format(irc
, "v", "TIME");
576 int irc_cmd_topic(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
580 PurpleChatConversation
*chat
;
585 chat
= purple_conversations_find_chat_with_account(target
, irc
->account
);
590 topic
= purple_chat_conversation_get_topic (chat
);
594 tmp
= g_markup_escape_text(topic
, -1);
595 tmp2
= purple_markup_linkify(tmp
);
596 buf
= g_strdup_printf(_("current topic is: %s"), tmp2
);
600 buf
= g_strdup(_("No topic is set"));
601 purple_conversation_write_system_message(
602 PURPLE_CONVERSATION(chat
), buf
, PURPLE_MESSAGE_NO_LOG
);
608 buf
= irc_format(irc
, "vt:", "TOPIC", target
, args
[0]);
615 int irc_cmd_wallops(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
619 if (!args
|| !args
[0])
622 if (!strcmp(cmd
, "wallops"))
623 buf
= irc_format(irc
, "v:", "WALLOPS", args
[0]);
624 else if (!strcmp(cmd
, "operwall"))
625 buf
= irc_format(irc
, "v:", "OPERWALL", args
[0]);
635 int irc_cmd_whois(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
639 if (!args
|| !args
[0])
643 buf
= irc_format(irc
, "vvn", "WHOIS", args
[0], args
[1]);
644 irc
->whois
.nick
= g_strdup(args
[1]);
646 buf
= irc_format(irc
, "vn", "WHOIS", args
[0]);
647 irc
->whois
.nick
= g_strdup(args
[0]);
656 int irc_cmd_whowas(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
660 if (!args
|| !args
[0])
663 buf
= irc_format(irc
, "vn", "WHOWAS", args
[0]);
665 irc
->whois
.nick
= g_strdup(args
[0]);
672 static void irc_do_mode(struct irc_conn
*irc
, const char *target
, const char *sign
, char **ops
)
681 if (ops
[i
+ 2] && ops
[i
+ 4]) {
682 g_snprintf(mode
, sizeof(mode
), "%s%s%s%s", sign
,
683 ops
[i
], ops
[i
+ 2], ops
[i
+ 4]);
684 buf
= irc_format(irc
, "vcvnnn", "MODE", target
, mode
,
685 ops
[i
+ 1], ops
[i
+ 3], ops
[i
+ 5]);
687 } else if (ops
[i
+ 2]) {
688 g_snprintf(mode
, sizeof(mode
), "%s%s%s",
689 sign
, ops
[i
], ops
[i
+ 2]);
690 buf
= irc_format(irc
, "vcvnn", "MODE", target
, mode
,
691 ops
[i
+ 1], ops
[i
+ 3]);
694 g_snprintf(mode
, sizeof(mode
), "%s%s", sign
, ops
[i
]);
695 buf
= irc_format(irc
, "vcvn", "MODE", target
, mode
, ops
[i
+ 1]);