2 * irc.c - this file is part of vomak - a very simple IRC bot
4 * Copyright 2008 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5 * Copyright 2008 Dominic Hopf <dh(at)dmaphy(dot)de>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
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 02110-1301, USA.
27 #include <sys/types.h>
29 #include <netinet/in.h>
30 #include <sys/socket.h>
41 #include <glib/gstdio.h>
51 static void irc_kick(irc_conn_t
*irc_conn
, const gchar
*nickname
);
52 static gboolean
irc_is_user_op(irc_conn_t
*irc_conn
, const gchar
*nickname
);
68 const goodies_t goodies
[] = {
69 { "!coffee", "A nice sexy waitress brings %s a big cup of coffee!" },
70 { "!coke", "A nice sexy waitress brings %s a cool bottle of coke!" },
71 { "!beer", "A nice sexy waitress brings %s a nice bottle of beer!" },
72 { "!tea", "A nice sexy waitress brings %s a cup of hot tea!" },
73 { "!pizza", "Someone calls Mario, and he brings %s a tasty hawaiian pizza!" },
77 gboolean
irc_query_names(gpointer data
)
79 irc_conn_t
*irc
= data
;
80 static gchar msg
[1024];
85 msg_len
= g_snprintf(msg
, sizeof msg
, "NAMES #%s\r\n", config
->channel
);
86 // send the message directly to avoid logging (prevent log file spamming)
87 send(irc
->socket
, msg
, msg_len
, MSG_NOSIGNAL
);
93 /* 'line' should be terminated by "\r\n" (CRLF) */
94 static void irc_log(irc_conn_t
*irc_conn
, const gchar
*line
, gboolean send
)
98 static gchar str
[256];
101 if (! irc_conn
->log_fd
)
106 strftime(str
, sizeof str
, "%F %T %z ", tp
);
108 log_line
= g_string_new(str
);
109 if (send
) // if we are sending a message, add our ident string
111 g_string_append_printf(log_line
, ":%s!n=%s@%s ",
112 config
->nickname
, config
->username
, config
->servername
);
114 g_string_append(log_line
, line
);
115 /* add \r\n if it is missing */
116 if (strncmp(log_line
->str
+ log_line
->len
- 2, "\r\n", 2) != 0)
118 g_string_append(log_line
, "\r\n");
120 fwrite(log_line
->str
, log_line
->len
, 1, irc_conn
->log_fd
);
121 fflush(irc_conn
->log_fd
);
122 g_string_free(log_line
, TRUE
);
126 static void irc_send_private_message(irc_conn_t
*irc_conn
, const gchar
*target
, const gchar
*format
, ...)
128 static gchar tmp_msg
[1024];
129 static gchar msg
[1024];
136 va_start(ap
, format
);
137 g_vsnprintf(tmp_msg
, sizeof tmp_msg
, format
, ap
);
140 msg_len
= g_snprintf(msg
, sizeof msg
, "PRIVMSG %s :%s, %s\r\n", target
, target
, tmp_msg
);
141 irc_send(irc_conn
, msg
, msg_len
);
145 static gchar
*get_nickname(const gchar
*line
, guint len
)
147 static gchar result
[20];
150 // :eht16!n=enrico@uvena.de PRIVMSG #eht16 :df
151 for (i
= 0; i
< len
; i
++)
153 if (line
[i
] == '!' || line
[i
] == '=' || j
>= 19)
159 result
[j
++] = line
[i
];
167 static gchar
*get_command_sender(const gchar
*line
, guint len
, const gchar
*command
)
170 gsize cmd_len
= strlen(command
);
172 // :eht16!n=enrico@uvena.de PRIVMSG GeanyTestBot :hi
173 for (i
= 0; i
< len
; i
++)
178 if (strncmp(command
, line
+ i
+ 1, cmd_len
) == 0)
180 static gchar name
[20];
181 g_snprintf(name
, sizeof(name
), "%s :", config
->nickname
);
182 // if the receiver of the message is me, then it's a private message and
183 // we return the sender's nickname, otherwise NULL
184 if (strncmp(name
, line
+ i
+ cmd_len
+ 2, strlen(config
->nickname
) + 2) == 0 ||
185 strncmp("KICK", command
, 4) == 0)
187 return get_nickname(line
, len
);
198 static gint
get_response(const gchar
*line
, guint len
)
200 static gchar result
[4];
202 gboolean in_response
= FALSE
;
204 // :kornbluth.freenode.net 353 GeanyTestBot @ #eht16 :GeanyTestBot eht16
205 // :kornbluth.freenode.net 366 GeanyTestBot #eht16 :End of /NAMES list.
206 for (i
= 0; i
< len
; i
++)
208 // before a response code
209 if (line
[i
] != ' ' && ! in_response
)
212 // after a response code
213 if (line
[i
] == ' ' && in_response
)
220 i
++; // skip the space
222 result
[j
++] = line
[i
];
231 const gchar
*irc_get_message(const gchar
*line
, guint len
)
233 static gchar result
[1024] = { 0 };
235 gint state
= 0; // represents the current part of the whole line, separated by spaces
237 // :eht16!n=enrico@uvena.de PRIVMSG #eht16 :df foo: var
239 for (i
= 0; i
< len
; i
++)
250 else if (line
[i
] != '\r' && line
[i
] != '\n')
252 result
[j
++] = line
[i
];
261 static const gchar
*irc_get_message_with_name(const gchar
*line
, guint len
, const gchar
*name
)
266 tmp
= irc_get_message(line
, len
);
267 name_len
= strlen(name
);
269 if (strncmp(tmp
, name
, name_len
) == 0)
276 // returns a nickname argument given to cmd, it may also be "cmd for nickname", then the "for" is
278 static const gchar
*get_argument_target(const gchar
*line
, guint len
, const gchar
*cmd
)
280 static gchar result
[20];
284 // :eht16!n=enrico@uvena.de PRIVMSG #eht16 :!beer for me
285 tmp
= irc_get_message(line
, len
);
288 parts
= g_strsplit(tmp
, " ", -1);
289 if (parts
== NULL
|| parts
[0] == NULL
)
295 // if cmd doesn't match, skip it
296 if (parts
[0] != NULL
&& strcmp(parts
[0], cmd
) != 0)
302 if (parts
[1] == NULL
)
308 if (strcmp("for", parts
[1]) == 0)
310 if (parts
[2] != NULL
)
312 if (strcmp(parts
[2], "me") == 0)
315 return NULL
; // if we return NULL, the nickname of the caller is used, aka "me"
318 g_strlcpy(result
, parts
[2], sizeof(result
));
321 g_strlcpy(result
, parts
[1], sizeof(result
));
323 else if (strcmp(parts
[1], "me") == 0)
326 return NULL
; // if we return NULL, the nickname of the caller is used, aka "me"
330 g_strlcpy(result
, parts
[1], sizeof(result
));
338 // Parses the line and puts the first argument in arg1, all further arguments are concatenated
339 // in arg2. arg1 and arg2 should be freed when no longer needed.
340 // If arg1 and arg2 were set successfully, TRUE is returned, if any error occurs, FALSE is returned
341 // and arg1 and arg2 are set to NULL.
342 static gboolean
get_argument_two(const gchar
*line
, guint len
, const gchar
*cmd
,
343 gchar
**arg1
, gchar
**arg2
)
351 // :eht16!n=enrico@uvena.de PRIVMSG #eht16 :!learn keyword text to be added
352 tmp
= irc_get_message(line
, len
);
354 // -> !learn keyword text to be added
355 parts
= g_strsplit(tmp
, " ", 3);
356 if (parts
== NULL
|| parts
[0] == NULL
)
362 // if cmd doesn't match, skip it
363 if (parts
[0] != NULL
&& strcmp(parts
[0], cmd
) != 0)
369 if (parts
[1] == NULL
|| parts
[2] == NULL
)
375 *arg1
= g_strdup(parts
[1]);
376 *arg2
= g_strdup(parts
[2]);
384 static void command_fortune(irc_conn_t
*irc_conn
)
386 GError
*error
= NULL
;
390 if (g_spawn_command_line_sync(config
->fortune_cmd
, &out
, &err
, NULL
, &error
))
394 gchar
**lines
= g_strsplit(out
, "\n", -1);
397 len
= g_strv_length(lines
);
398 for (i
= 0; i
< len
; i
++)
400 if (strlen(g_strchomp(lines
[i
])) > 0)
401 irc_send_message(irc_conn
, NULL
, lines
[i
]);
407 vomak_warning("Executing fortune failed (%s)", err
);
414 vomak_warning("Executing fortune failed (%s)", error
->message
);
420 static void command_moo(irc_conn_t
*irc_conn
)
422 gint32 rand
= g_random_int();
427 const gchar
*moo_str
[] = {
434 "..\"Have you mooed today?\"..\r\n",
438 for (i
= 0; moo_str
[i
] != NULL
; i
++)
440 irc_send_message(irc_conn
, NULL
, moo_str
[i
]);
445 irc_send_message(irc_conn
, NULL
, "I have Super Cow Powers. Have you mooed today?");
450 static void command_learn(irc_conn_t
*irc_conn
, const gchar
*line
, guint len
)
454 if (get_argument_two(line
, len
, "!learn", &arg1
, &arg2
))
456 gint result
= help_system_learn(arg1
, arg2
);
463 text
= g_strdup_printf("new keyword \"%s\" was added.", arg1
);
468 text
= g_strdup_printf("existing keyword \"%s\" was updated.", arg1
);
473 text
= g_strdup("an error occurred. Database not updated.");
477 irc_send_message(irc_conn
, get_nickname(line
, len
), "%s", text
);
484 irc_send_message(irc_conn
, get_nickname(line
, len
),
485 "wrong usage of !learn. Use \"?? learn\" for usage information.");
489 static void command_alias(irc_conn_t
*irc_conn
, const gchar
*line
, guint len
)
493 if (get_argument_two(line
, len
, "!alias", &arg1
, &arg2
))
495 // detect if arg2 has more than one word by scanning for spaces in
497 if (strchr(arg2
, ' '))
499 irc_send_message(irc_conn
, get_nickname(line
, len
),
500 "You gave me more than two arguments for !alias. I can not handle this.");
502 // check if the target actually exist and refuse if it doesn't exist
503 else if (g_hash_table_lookup(config
->data
, arg2
) == NULL
)
505 irc_send_message(irc_conn
, get_nickname(line
, len
),
506 "The given target for the alias does not exist. I will refuse your request.");
512 gchar
*alias
= g_strconcat("@", arg2
, NULL
);
514 result
= help_system_learn(arg1
, alias
);
520 text
= g_strdup_printf("new alias \"%s\" was added.", arg1
);
525 text
= g_strdup_printf("existing alias \"%s\" was updated.", arg1
);
530 text
= g_strdup("An error occurred. Database not updated.");
535 irc_send_message(irc_conn
, get_nickname(line
, len
), "%s", text
);
544 irc_send_message(irc_conn
, get_nickname(line
, len
),
545 "wrong usage of !alias. Use \"?? alias\" for usage information.");
549 static void command_goodies(irc_conn_t
*irc_conn
, const gchar
*line
, guint len
, gint goodie
)
551 const goodies_t
*g
= &goodies
[goodie
];
552 const gchar
*arg
= get_argument_target(line
, len
, g
->command
);
555 arg
= get_nickname(line
, len
);
557 irc_send_message(irc_conn
, NULL
,
562 static void process_command(irc_conn_t
*irc_conn
, const gchar
*line
, guint len
, const gchar
*content
)
565 if (strncmp(content
, "!test", 5) == 0)
567 irc_send_message(irc_conn
, get_nickname(line
, len
), "I don't like tests!");
570 else if (strncmp(content
, "!moo", 4) == 0)
572 command_moo(irc_conn
);
575 else if (config
->fortune_cmd
!= NULL
&& strncmp(content
, "!fortune", 8) == 0)
577 command_fortune(irc_conn
);
580 else if (strncmp(content
, "!coffee", 7) == 0)
582 command_goodies(irc_conn
, line
, len
, GOODIES_COFFEE
);
585 else if (strncmp(content
, "!coke", 5) == 0)
587 command_goodies(irc_conn
, line
, len
, GOODIES_COKE
);
590 else if (strncmp(content
, "!beer", 5) == 0)
592 command_goodies(irc_conn
, line
, len
, GOODIES_BEER
);
595 else if (strncmp(content
, "!pizza", 5) == 0)
597 command_goodies(irc_conn
, line
, len
, GOODIES_PIZZA
);
600 else if (strncmp(content
, "!tea", 5) == 0)
602 command_goodies(irc_conn
, line
, len
, GOODIES_TEA
);
605 else if (strncmp(content
, "!help", 5) == 0)
607 help_system_query("?? help");
611 * You have to register your bot with nickserv and add it to the access-list
612 * of your channel to make the !roulette-command work.
613 * This is just tested on FreeNode. Please feel free to write patches, that
614 * will make this work on other Networks.
616 else if (strncmp(content
, "!roulette", 9) == 0)
618 static gint32 rand
= -1;
619 static gint bullets_fired
= 0;
622 rand
= g_random_int() % 6;
623 if (rand
== bullets_fired
)
625 irc_send_message(irc_conn
, NULL
, "*bang*");
626 irc_kick(irc_conn
, get_nickname(line
, len
));
627 rand
= g_random_int() % 6;
633 irc_send_message(irc_conn
, NULL
, "*click*");
638 /// TODO require op privileges for !learn
639 else if (strncmp(content
, "!learn", 6) == 0)
641 command_learn(irc_conn
, line
, len
);
644 else if (strncmp(content
, "!alias", 6) == 0)
646 command_alias(irc_conn
, line
, len
);
651 static gboolean
process_line(irc_conn_t
*irc_conn
, const gchar
*line
, guint len
)
653 static gchar msg
[1024];
655 gint response
= get_response(line
, len
);
656 static gchar tmp_userlist
[1024];
658 const gchar
*content
;
659 static gboolean connected
= FALSE
;
661 // don't log the NAMES command's output (prevent log file spam)
662 if (response
!= 353 && response
!= 366)
663 irc_log(irc_conn
, line
, FALSE
);
665 // An error occurred, try to quit cleanly and print the error
666 if ((response
> 400 && response
< 503))
668 // ignore Freenode's info messages sent with error code 477
669 // (see http://freenode.net/faq.shtml#freenode-info)
670 if (response
!= 477 || strstr(line
, "[freenode-info]") == NULL
)
673 syslog(LOG_WARNING
, "received error: %d (%s)", response
, g_strstrip((gchar
*) line
));
675 g_print("Error: %s", line
);
677 g_free(irc_conn
->quit_msg
);
678 irc_conn
->quit_msg
= g_strdup("I got an error and better leave in advance. Bye.");
679 irc_goodbye(irc_conn
);
693 content
= irc_get_message(line
, len
);
695 // retrieve user name list
698 if (tmp_userlist
[0] == '\0')
699 g_strlcpy(tmp_userlist
, strchr(content
, ':') + 1, sizeof(tmp_userlist
));
701 g_strlcat(tmp_userlist
, strchr(content
, ':') + 1, sizeof(tmp_userlist
));
703 // retrieve end of user name list
704 else if (response
== 366)
706 if (tmp_userlist
[0] != '\0')
708 set_user_list(tmp_userlist
);
709 tmp_userlist
[0] = '\0';
712 else if (! connected
)
714 // don't do anything else until we got finished connecting (to skip MOTD messages)
717 else if (strncmp("PING :", line
, 6) == 0)
719 msg_len
= g_snprintf(msg
, sizeof msg
, "PONG %s\r\n", line
+ 6); // 7 = "PING :"
720 debug("PONG: -%s-\n", msg
);
721 irc_send(irc_conn
, msg
, msg_len
);
723 // handle private message
724 else if ((priv_sender
= get_command_sender(line
, len
, "PRIVMSG")) != NULL
)
726 // to be able to send private messages to users, you need to register your bot's
727 // nickname with Nickserv (at least on Freenode)
728 irc_send_private_message(irc_conn
, priv_sender
, "I don't like private messages!");
730 // handle kicks (we were kicked, bastards)
731 else if (get_command_sender(line
, len
, "KICK") != NULL
)
733 if (config
->auto_rejoin
)
735 g_usleep(5000000); // just wait a little bit
736 msg_len
= g_snprintf(msg
, sizeof msg
, "JOIN #%s\r\n", config
->channel
);
737 irc_send(irc_conn
, msg
, msg_len
);
744 // Hi /me, acts on "hello $nickname" and "hi $nickname", hi and hello are case-insensitive
746 else if (strstr(content
, config
->nickname
) != NULL
)
748 const gchar
*tmp_msg
= irc_get_message_with_name(line
, len
, config
->nickname
);
750 if (strncasecmp("hi", content
, 2) == 0 || strncasecmp("hello", content
, 5) == 0 || strncasecmp("hey", content
, 3) == 0 ||
751 strcasecmp(", hi", tmp_msg
) == 0 || strcasecmp(", hello", tmp_msg
) == 0 || strcasecmp(", hey", tmp_msg
) == 0 ||
752 strcasecmp(": hi", tmp_msg
) == 0 || strcasecmp(": hello", tmp_msg
) == 0 || strcasecmp(": hey", tmp_msg
) == 0)
754 irc_send_message(irc_conn
, NULL
,
755 "Hi %s. My name is %s and I'm here to offer additional services to you! "
756 "Try \"?? help\" for general information and \"?? vomak\" for information about me.",
757 get_nickname(line
, len
), config
->nickname
);
759 else if (strncasecmp("thanks", content
, 6) == 0 || strncasecmp("thx", content
, 3) == 0 ||
760 strcasecmp(", thanks", tmp_msg
) == 0 || strcasecmp(", thx", tmp_msg
) == 0 ||
761 strcasecmp(": thanks", tmp_msg
) == 0 || strcasecmp(": thx", tmp_msg
) == 0)
763 irc_send_message(irc_conn
, get_nickname(line
, len
),
764 "no problem. It was a pleasure to serve you.");
768 else if (strncmp(content
, "?? ", 3) == 0)
770 help_system_query(content
);
772 // pass to process_command() to process other commands (!beer, !test, !learn, ...)
773 else if (*content
== '!')
775 process_command(irc_conn
, line
, len
, content
);
783 * Please note that this will not work on Networks without ChanServ, e.g. on
784 * Quakenet or IRCnet. Your Bot has to be registered with NickServ and to be
785 * added to the channel access list for this to work.
787 static gboolean
irc_toggle_op(irc_conn_t
*irc_conn
, gboolean request_op
)
790 static gchar msg
[1024];
793 if (irc_is_user_op(irc_conn
, "ChanServ"))
795 cmd
= (request_op
) ? "op" : "deop";
796 msg_len
= g_snprintf(msg
, sizeof msg
, "PRIVMSG ChanServ :%s #%s\r\n", cmd
, config
->channel
);
797 irc_send(irc_conn
, msg
, msg_len
);
801 return FALSE
; /* it seems we don't have a ChanServ bot */
805 static gboolean
irc_is_user_op(irc_conn_t
*irc_conn
, const gchar
*nickname
)
808 const gchar
*userlist
;
810 if (nickname
== NULL
)
813 userlist
= get_user_list();
815 if ( (pos
= strstr(userlist
, nickname
)) )
817 if ( (pos
- 1) >= userlist
&& (*(pos
- 1) == '@') )
825 irc_send_message(irc_conn
, NULL
,
826 "Hey. There are crazy things going on here. (O.o)");
828 syslog(LOG_WARNING
, "user %s not found in names list of #%s", nickname
, config
->channel
);
836 static void irc_kick(irc_conn_t
*irc_conn
, const gchar
*nickname
)
838 static gchar msg
[1024];
839 gboolean need_deop
= FALSE
;
844 if (! irc_is_user_op(irc_conn
, config
->nickname
))
846 // if irc_toggle_op fails, most probably we don't have a ChanServ and at this point we
847 // know we are not an op, so fail silently and don't try to kick
848 if (! irc_toggle_op(irc_conn
, TRUE
)) /// TODO: prĂ¼fen, ob das auch erfolreich war
853 // give the server a chance to set the op status for us before we make us of it,
854 // and let the victim read his *bang* message
857 msg_len
= g_snprintf(msg
, sizeof msg
, "KICK #%s %s\r\n", config
->channel
, nickname
);
858 irc_send(irc_conn
, msg
, msg_len
);
860 irc_toggle_op(irc_conn
, FALSE
);
864 static gboolean
input_cb(GIOChannel
*source
, GIOCondition cond
, gpointer data
)
869 irc_conn_t
*irc
= data
;
872 if (cond
& (G_IO_ERR
| G_IO_HUP
))
875 if ((buf_len
= socket_fd_gets(irc
->socket
, buf
, sizeof(buf
))) != -1)
877 ret
= process_line(irc
, buf
, buf_len
);
881 irc_conn_t
*irc
= data
;
883 if (cond
& (G_IO_IN
| G_IO_PRI
))
891 rv
= g_io_channel_read_line(source
, &buf
, &buf_len
, NULL
, &err
);
895 buf
[buf_len
] = '\0'; // skip trailing \r\n
897 process_line(irc
, buf
, buf_len
);
902 debug("%s: error: %s", __func__
, err
->message
);
907 while (rv
== G_IO_STATUS_NORMAL
|| rv
== G_IO_STATUS_AGAIN
);
908 debug("%s: status %d\n", __func__
, rv
);
915 void irc_send_message(irc_conn_t
*irc_conn
, const gchar
*target
, const gchar
*format
, ...)
917 static gchar tmp_msg
[1024];
918 static gchar msg
[1024];
922 va_start(ap
, format
);
923 g_vsnprintf(tmp_msg
, sizeof tmp_msg
, format
, ap
);
927 msg_len
= g_snprintf(msg
, sizeof msg
, "PRIVMSG #%s :%s, %s\r\n", config
->channel
, target
, tmp_msg
);
929 msg_len
= g_snprintf(msg
, sizeof msg
, "PRIVMSG #%s :%s\r\n", config
->channel
, tmp_msg
);
931 irc_send(irc_conn
, msg
, msg_len
);
936 * target should not be NULL!
938 void irc_send_notice(irc_conn_t
*irc_conn
, const gchar
*target
, const gchar
*format
, ...)
940 static gchar tmp_msg
[1024];
941 static gchar msg
[1024];
945 va_start(ap
, format
);
946 g_vsnprintf(tmp_msg
, sizeof tmp_msg
, format
, ap
);
949 msg_len
= g_snprintf(msg
, sizeof msg
, "NOTICE #%s :%s, %s\r\n", config
->channel
, target
, tmp_msg
);
951 irc_send(irc_conn
, msg
, msg_len
);
955 // simple wrapper for send() to enable logging for sent commands
956 gint
irc_send(irc_conn_t
*irc_conn
, const gchar
*msg
, guint msg_len
)
958 irc_log(irc_conn
, msg
, TRUE
);
959 return send(irc_conn
->socket
, msg
, msg_len
, MSG_NOSIGNAL
);
963 void irc_goodbye(irc_conn_t
*irc
)
968 if (NZV(irc
->quit_msg
))
969 len
= g_snprintf(msg
, sizeof msg
, "QUIT :%s\r\n", irc
->quit_msg
);
971 len
= g_strlcpy(msg
, "QUIT :Good bye. It was a pleasure to serve you\r\n", sizeof msg
);
972 irc_send(irc
, msg
, len
);
976 void irc_logfile_reopen(irc_conn_t
*irc_conn
)
980 if (irc_conn
->log_fd
!= NULL
)
981 fclose(irc_conn
->log_fd
);
983 if (NZV(config
->logfile
))
985 irc_conn
->log_fd
= g_fopen(config
->logfile
, "a");
986 if (! irc_conn
->log_fd
)
987 vomak_warning("Logfile could not be opened.");
992 gint
irc_finalize(irc_conn_t
*irc_conn
)
994 if (irc_conn
->socket
< 0)
997 if (irc_conn
->lock_tag
> 0)
998 g_source_remove(irc_conn
->lock_tag
);
1000 if (irc_conn
->log_fd
!= NULL
)
1002 irc_log(irc_conn
, "Stop logging\r\n", FALSE
);
1003 fclose(irc_conn
->log_fd
);
1006 if (irc_conn
->read_ioc
)
1008 g_io_channel_shutdown(irc_conn
->read_ioc
, TRUE
, NULL
);
1009 g_io_channel_unref(irc_conn
->read_ioc
);
1010 irc_conn
->read_ioc
= NULL
;
1012 socket_fd_close(irc_conn
->socket
);
1013 irc_conn
->socket
= -1;
1015 g_free(irc_conn
->quit_msg
);
1021 void irc_connect(irc_conn_t
*irc_conn
)
1024 struct sockaddr_in their_addr
;
1030 // Connect the socket to the server
1031 if ((he
= gethostbyname(config
->server
)) == NULL
)
1033 perror("gethostbyname");
1037 if ((irc_conn
->socket
= socket(PF_INET
, SOCK_STREAM
, 0)) == -1)
1043 their_addr
.sin_family
= PF_INET
;
1044 their_addr
.sin_port
= htons(6667);
1045 their_addr
.sin_addr
= *((struct in_addr
*)he
->h_addr_list
[0]);
1046 memset(&(their_addr
.sin_zero
), '\0', 8);
1048 if (connect(irc_conn
->socket
, (struct sockaddr
*)&their_addr
, sizeof(struct sockaddr
)) == -1)
1054 if (NZV(config
->logfile
))
1056 irc_conn
->log_fd
= g_fopen(config
->logfile
, "a");
1057 if (irc_conn
->log_fd
)
1058 irc_log(irc_conn
, "Start logging\r\n", FALSE
);
1060 vomak_warning("Logfile could not be opened.");
1063 msg_len
= g_snprintf(msg
, sizeof(msg
), "USER %s %s %s :%s\r\n",
1064 config
->username
, config
->servername
, config
->servername
, config
->realname
);
1065 if (irc_send(irc_conn
, msg
, msg_len
) == -1)
1067 perror("send USER");
1069 // and how we are called
1070 msg_len
= g_snprintf(msg
, sizeof(msg
), "NICK %s\r\n", config
->nickname
);
1071 if (irc_send(irc_conn
, msg
, msg_len
) == -1)
1073 perror("send NICK");
1075 // identify our nick
1076 if (NZV(config
->nickserv_password
))
1078 msg_len
= g_snprintf(msg
, sizeof(msg
), "PRIVMSG nickserv :identify %s\r\n", config
->nickserv_password
);
1079 // don't use irc_send() here, no need to log our password
1080 if (send(irc_conn
->socket
, msg
, msg_len
, MSG_NOSIGNAL
) == -1)
1082 perror("send NICKSERV");
1086 msg_len
= g_snprintf(msg
, sizeof msg
, "JOIN #%s\r\n", config
->channel
);
1087 if (irc_send(irc_conn
, msg
, msg_len
) == -1)
1092 // input callback, attached to the main loop
1093 irc_conn
->read_ioc
= g_io_channel_unix_new(irc_conn
->socket
);
1094 //~ g_io_channel_set_flags(irc_conn.read_ioc, G_IO_FLAG_NONBLOCK, NULL);
1095 g_io_channel_set_encoding(irc_conn
->read_ioc
, NULL
, NULL
);
1096 irc_conn
->lock_tag
= g_io_add_watch(irc_conn
->read_ioc
, G_IO_IN
|G_IO_PRI
|G_IO_ERR
, input_cb
, irc_conn
);