4 * Copyright (C) 2003, Ethan Blanton <eblanton@cs.purdue.edu>
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
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
27 static void irc_do_mode(struct irc_conn
*irc
, const char *target
, const char *sign
, char **ops
);
29 int irc_cmd_default(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
31 PurpleConversation
*convo
= purple_conversations_find_with_account(target
, irc
->account
);
37 buf
= g_strdup_printf(_("Unknown command: %s"), cmd
);
38 purple_conversation_write_system_message(convo
, buf
, PURPLE_MESSAGE_NO_LOG
);
44 int irc_cmd_away(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
48 if (args
[0] && !purple_strequal(cmd
, "back")) {
49 message
= purple_markup_strip_html(args
[0]);
50 purple_util_chrreplace(message
, '\n', ' ');
51 buf
= irc_format(irc
, "v:", "AWAY", message
);
54 buf
= irc_format(irc
, "v", "AWAY");
62 int irc_cmd_ctcp(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
64 /* we have defined args as args[0] is target and args[1] is ctcp command */
68 /* check if we have args */
69 if (!args
|| !args
[0] || !args
[1])
72 /* TODO:strip newlines or send each line as separate ctcp or something
73 * actually, this shouldn't be done here but somewhere else since irc should support escaping newlines */
75 string
= g_string_new(args
[1]);
76 g_string_prepend_c (string
,'\001');
77 g_string_append_c (string
,'\001');
78 buf
= irc_format(irc
, "vn:", "PRIVMSG", args
[0], string
->str
);
79 g_string_free(string
,TRUE
);
87 int irc_cmd_ctcp_action(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
89 PurpleConnection
*gc
= purple_account_get_connection(irc
->account
);
90 char *action
, *escaped
, *dst
, **newargs
;
93 PurpleConversation
*convo
;
96 if (!args
|| !args
[0] || !gc
)
99 convo
= purple_conversations_find_with_account(target
, irc
->account
);
101 msg
= g_strdup_printf("/me %s", args
[0]);
103 /* XXX: we'd prefer to keep this in conversation.c */
104 if (PURPLE_IS_IM_CONVERSATION(convo
)) {
105 pmsg
= purple_message_new_outgoing(
106 purple_conversation_get_name(convo
), msg
, 0);
108 purple_signal_emit(purple_conversations_get_handle(),
109 "sending-im-msg", irc
->account
, pmsg
);
111 pmsg
= purple_message_new_outgoing(NULL
, msg
, 0);
113 purple_signal_emit(purple_conversations_get_handle(),
114 "sending-chat-msg", irc
->account
, pmsg
,
115 purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(convo
)));
119 if (purple_message_is_empty(pmsg
))
121 msg
= g_strdup(purple_message_get_contents(pmsg
)); /* XXX: is it really necessary? */
123 if (strncmp(msg
, "/me ", 4) != 0) {
124 newargs
= g_new0(char *, 2);
125 newargs
[0] = g_strdup(target
);
128 irc_cmd_privmsg(irc
, cmd
, target
, (const char **)newargs
);
133 action
= g_malloc(strlen(&msg
[4]) + 10);
135 sprintf(action
, "\001ACTION ");
141 if (*(src
+ 1) == '\0') {
154 newargs
= g_new0(char *, 2);
155 newargs
[0] = g_strdup(target
);
157 irc_cmd_privmsg(irc
, cmd
, target
, (const char **)newargs
);
163 /* XXX: we'd prefer to keep this in conversation.c */
164 if (PURPLE_IS_IM_CONVERSATION(convo
)) {
165 purple_signal_emit(purple_conversations_get_handle(),
166 "sent-im-msg", irc
->account
, pmsg
);
168 purple_signal_emit(purple_conversations_get_handle(),
169 "sent-chat-msg", irc
->account
, pmsg
,
170 purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(convo
)));
176 escaped
= g_markup_escape_text(args
[0], -1);
177 action
= g_strdup_printf("/me %s", escaped
);
179 if (action
[strlen(action
) - 1] == '\n')
180 action
[strlen(action
) - 1] = '\0';
181 if (PURPLE_IS_CHAT_CONVERSATION(convo
))
182 purple_serv_got_chat_in(gc
, purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(convo
)),
183 purple_connection_get_display_name(gc
),
184 PURPLE_MESSAGE_SEND
, action
, time(NULL
));
186 purple_conversation_write_message(convo
, purple_message_new_outgoing(
187 purple_connection_get_display_name(gc
), action
, 0));
194 int irc_cmd_ctcp_version(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
198 if (!args
|| !args
[0])
201 buf
= irc_format(irc
, "vn:", "PRIVMSG", args
[0], "\001VERSION\001");
208 int irc_cmd_invite(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
212 if (!args
|| !args
[0] || !(args
[1] || target
))
215 buf
= irc_format(irc
, "vnc", "INVITE", args
[0], args
[1] ? args
[1] : target
);
222 int irc_cmd_join(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
226 if (!args
|| !args
[0])
230 buf
= irc_format(irc
, "vcv", "JOIN", args
[0], args
[1]);
232 buf
= irc_format(irc
, "vc", "JOIN", args
[0]);
239 int irc_cmd_kick(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
243 if (!args
|| !args
[0])
246 if (!purple_conversations_find_chat_with_account(target
, irc
->account
))
250 buf
= irc_format(irc
, "vcn:", "KICK", target
, args
[0], args
[1]);
252 buf
= irc_format(irc
, "vcn", "KICK", target
, args
[0]);
259 int irc_cmd_list(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
261 purple_roomlist_show_with_account(irc
->account
);
266 int irc_cmd_mode(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
268 PurpleConnection
*gc
;
274 if (purple_strequal(cmd
, "mode")) {
275 if (!args
[0] && irc_ischannel(target
))
276 buf
= irc_format(irc
, "vc", "MODE", target
);
277 else if (args
[0] && (*args
[0] == '+' || *args
[0] == '-'))
278 buf
= irc_format(irc
, "vcn", "MODE", target
, args
[0]);
280 buf
= irc_format(irc
, "vn", "MODE", args
[0]);
283 } else if (purple_strequal(cmd
, "umode")) {
286 gc
= purple_account_get_connection(irc
->account
);
287 buf
= irc_format(irc
, "vnc", "MODE", purple_connection_get_display_name(gc
), args
[0]);
298 int irc_cmd_names(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
302 if (!args
|| (!args
[0] && !irc_ischannel(target
)))
305 buf
= irc_format(irc
, "vc", "NAMES", args
[0] ? args
[0] : target
);
312 int irc_cmd_nick(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
316 if (!args
|| !args
[0])
319 buf
= irc_format(irc
, "v:", "NICK", args
[0]);
320 g_free(irc
->reqnick
);
321 irc
->reqnick
= g_strdup(args
[0]);
322 irc
->nickused
= FALSE
;
329 int irc_cmd_op(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
331 char **nicks
, **ops
, *sign
, *mode
;
334 if (!args
|| !args
[0] || !*args
[0])
337 if (purple_strequal(cmd
, "op")) {
340 } else if (purple_strequal(cmd
, "deop")) {
343 } else if (purple_strequal(cmd
, "voice")) {
346 } else if (purple_strequal(cmd
, "devoice")) {
350 purple_debug(PURPLE_DEBUG_ERROR
, "irc", "invalid 'op' command '%s'\n", cmd
);
354 nicks
= g_strsplit(args
[0], " ", -1);
356 for (i
= 0; nicks
[i
]; i
++)
358 ops
= g_new0(char *, i
* 2 + 1);
360 for (i
= 0; nicks
[i
]; i
++) {
363 ops
[used
++] = nicks
[i
];
367 irc_do_mode(irc
, target
, sign
, ops
);
374 int irc_cmd_part(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
382 buf
= irc_format(irc
, "vc:", "PART", args
[0] ? args
[0] : target
, args
[1]);
384 buf
= irc_format(irc
, "vc", "PART", args
[0] ? args
[0] : target
);
391 int irc_cmd_ping(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
396 if (args
&& args
[0]) {
397 if (irc_ischannel(args
[0]))
399 stamp
= g_strdup_printf("\001PING %lu\001", time(NULL
));
400 buf
= irc_format(irc
, "vn:", "PRIVMSG", args
[0], stamp
);
403 stamp
= g_strdup_printf("%s %lu", target
, time(NULL
));
404 buf
= irc_format(irc
, "v:", "PING", stamp
);
407 stamp
= g_strdup_printf("%lu", time(NULL
));
408 buf
= irc_format(irc
, "vv", "PING", stamp
);
417 int irc_cmd_privmsg(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
419 int max_privmsg_arg_len
;
420 const char *cur
, *end
;
424 if (!args
|| !args
[0] || !args
[1])
427 max_privmsg_arg_len
= IRC_MAX_MSG_SIZE
- strlen(args
[0]) - 64;
428 salvaged
= purple_utf8_salvage(args
[1]);
431 while (*end
&& *cur
) {
432 end
= strchr(cur
, '\n');
434 end
= cur
+ strlen(cur
);
435 if (end
- cur
> max_privmsg_arg_len
) {
436 /* this call is used to find the last valid character position in the first
437 * max_privmsg_arg_len bytes of the utf-8 message
439 g_utf8_validate(cur
, max_privmsg_arg_len
, &end
);
442 msg
= g_strndup(cur
, end
- cur
);
444 if(purple_strequal(cmd
, "notice"))
445 buf
= irc_format(irc
, "vt:", "NOTICE", args
[0], msg
);
447 buf
= irc_format(irc
, "vt:", "PRIVMSG", args
[0], msg
);
463 int irc_cmd_quit(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
467 if (!irc
->quitting
) {
469 * Use purple_account_get_string(irc->account, "quitmsg", IRC_DEFAULT_QUIT)
470 * and uncomment the appropriate account preference in irc.c if we
471 * decide we want custom quit messages.
473 buf
= irc_format(irc
, "v:", "QUIT", (args
&& args
[0]) ? args
[0] : IRC_DEFAULT_QUIT
);
477 irc
->quitting
= TRUE
;
479 if (!purple_account_is_disconnecting(irc
->account
))
480 purple_account_set_status(irc
->account
, "offline", TRUE
, NULL
);
486 int irc_cmd_quote(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
490 if (!args
|| !args
[0])
493 buf
= irc_format(irc
, "n", args
[0]);
500 int irc_cmd_query(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
502 PurpleIMConversation
*im
;
503 PurpleConnection
*gc
;
505 if (!args
|| !args
[0])
508 im
= purple_im_conversation_new(irc
->account
, args
[0]);
509 purple_conversation_present(PURPLE_CONVERSATION(im
));
512 gc
= purple_account_get_connection(irc
->account
);
513 irc_cmd_privmsg(irc
, cmd
, target
, args
);
514 purple_conversation_write_message(PURPLE_CONVERSATION(im
),
515 purple_message_new_outgoing(
516 purple_connection_get_display_name(gc
), args
[1], 0));
522 int irc_cmd_remove(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
526 if (!args
|| !args
[0])
529 if (!irc_ischannel(target
)) /* not a channel, punt */
533 buf
= irc_format(irc
, "vcn:", "REMOVE", target
, args
[0], args
[1]);
535 buf
= irc_format(irc
, "vcn", "REMOVE", target
, args
[0]);
542 int irc_cmd_service(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
544 char *capital_cmd
, *buf
;
546 if (!args
|| !args
[0])
549 /* cmd will be one of nickserv, chanserv, memoserv or operserv */
550 capital_cmd
= g_ascii_strup(cmd
, -1);
551 buf
= irc_format(irc
, "v:", capital_cmd
, args
[0]);
559 int irc_cmd_time(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
563 buf
= irc_format(irc
, "v", "TIME");
570 int irc_cmd_topic(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
574 PurpleChatConversation
*chat
;
579 chat
= purple_conversations_find_chat_with_account(target
, irc
->account
);
584 topic
= purple_chat_conversation_get_topic (chat
);
588 tmp
= g_markup_escape_text(topic
, -1);
589 tmp2
= purple_markup_linkify(tmp
);
590 buf
= g_strdup_printf(_("current topic is: %s"), tmp2
);
594 buf
= g_strdup(_("No topic is set"));
595 purple_conversation_write_system_message(
596 PURPLE_CONVERSATION(chat
), buf
, PURPLE_MESSAGE_NO_LOG
);
602 buf
= irc_format(irc
, "vt:", "TOPIC", target
, args
[0]);
609 int irc_cmd_wallops(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
613 if (!args
|| !args
[0])
616 if (purple_strequal(cmd
, "wallops"))
617 buf
= irc_format(irc
, "v:", "WALLOPS", args
[0]);
618 else if (purple_strequal(cmd
, "operwall"))
619 buf
= irc_format(irc
, "v:", "OPERWALL", args
[0]);
629 int irc_cmd_whois(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
633 if (!args
|| !args
[0])
637 buf
= irc_format(irc
, "vvn", "WHOIS", args
[0], args
[1]);
638 irc
->whois
.nick
= g_strdup(args
[1]);
640 buf
= irc_format(irc
, "vn", "WHOIS", args
[0]);
641 irc
->whois
.nick
= g_strdup(args
[0]);
650 int irc_cmd_whowas(struct irc_conn
*irc
, const char *cmd
, const char *target
, const char **args
)
654 if (!args
|| !args
[0])
657 buf
= irc_format(irc
, "vn", "WHOWAS", args
[0]);
659 irc
->whois
.nick
= g_strdup(args
[0]);
666 static void irc_do_mode(struct irc_conn
*irc
, const char *target
, const char *sign
, char **ops
)
675 if (ops
[i
+ 2] && ops
[i
+ 4]) {
676 g_snprintf(mode
, sizeof(mode
), "%s%s%s%s", sign
,
677 ops
[i
], ops
[i
+ 2], ops
[i
+ 4]);
678 buf
= irc_format(irc
, "vcvnnn", "MODE", target
, mode
,
679 ops
[i
+ 1], ops
[i
+ 3], ops
[i
+ 5]);
681 } else if (ops
[i
+ 2]) {
682 g_snprintf(mode
, sizeof(mode
), "%s%s%s",
683 sign
, ops
[i
], ops
[i
+ 2]);
684 buf
= irc_format(irc
, "vcvnn", "MODE", target
, mode
,
685 ops
[i
+ 1], ops
[i
+ 3]);
688 g_snprintf(mode
, sizeof(mode
), "%s%s", sign
, ops
[i
]);
689 buf
= irc_format(irc
, "vcvn", "MODE", target
, mode
, ops
[i
+ 1]);