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
delayed_quit(gpointer data
)
658 static gboolean
process_line(irc_conn_t
*irc_conn
, const gchar
*line
, guint len
)
660 static gchar msg
[1024];
662 gint response
= get_response(line
, len
);
663 static gchar tmp_userlist
[1024];
665 const gchar
*content
;
666 static gboolean connected
= FALSE
;
668 // don't log the NAMES command's output (prevent log file spam)
669 if (response
!= 353 && response
!= 366)
670 irc_log(irc_conn
, line
, FALSE
);
672 // An error occurred, try to quit cleanly and print the error
673 if ((response
> 400 && response
< 503))
675 // ignore Freenode's info messages sent with error code 477
676 // (see http://freenode.net/faq.shtml#freenode-info)
677 if (response
!= 477 || strstr(line
, "[freenode-info]") == NULL
)
680 syslog(LOG_WARNING
, "received error: %d (%s)", response
, g_strstrip((gchar
*) line
));
682 g_print("Error: %s", line
);
684 g_free(irc_conn
->quit_msg
);
685 irc_conn
->quit_msg
= g_strdup("I got an error and better leave in advance. Bye.");
686 irc_goodbye(irc_conn
);
687 g_timeout_add_seconds(1, delayed_quit
, NULL
);
700 content
= irc_get_message(line
, len
);
702 // retrieve user name list
705 if (tmp_userlist
[0] == '\0')
706 g_strlcpy(tmp_userlist
, strchr(content
, ':') + 1, sizeof(tmp_userlist
));
708 g_strlcat(tmp_userlist
, strchr(content
, ':') + 1, sizeof(tmp_userlist
));
710 // retrieve end of user name list
711 else if (response
== 366)
713 if (tmp_userlist
[0] != '\0')
715 set_user_list(tmp_userlist
);
716 tmp_userlist
[0] = '\0';
719 else if (! connected
)
721 // don't do anything else until we got finished connecting (to skip MOTD messages)
724 else if (strncmp("PING :", line
, 6) == 0)
726 msg_len
= g_snprintf(msg
, sizeof msg
, "PONG %s\r\n", line
+ 6); // 7 = "PING :"
727 debug("PONG: -%s-\n", msg
);
728 irc_send(irc_conn
, msg
, msg_len
);
730 // handle private message
731 else if ((priv_sender
= get_command_sender(line
, len
, "PRIVMSG")) != NULL
)
733 // to be able to send private messages to users, you need to register your bot's
734 // nickname with Nickserv (at least on Freenode)
735 irc_send_private_message(irc_conn
, priv_sender
, "I don't like private messages!");
737 // handle kicks (we were kicked, bastards)
738 else if (get_command_sender(line
, len
, "KICK") != NULL
)
740 if (config
->auto_rejoin
)
742 g_usleep(5000000); // just wait a little bit
743 msg_len
= g_snprintf(msg
, sizeof msg
, "JOIN #%s\r\n", config
->channel
);
744 irc_send(irc_conn
, msg
, msg_len
);
751 // Hi /me, acts on "hello $nickname" and "hi $nickname", hi and hello are case-insensitive
753 else if (strstr(content
, config
->nickname
) != NULL
)
755 const gchar
*tmp_msg
= irc_get_message_with_name(line
, len
, config
->nickname
);
757 if (strncasecmp("hi", content
, 2) == 0 || strncasecmp("hello", content
, 5) == 0 || strncasecmp("hey", content
, 3) == 0 ||
758 strcasecmp(", hi", tmp_msg
) == 0 || strcasecmp(", hello", tmp_msg
) == 0 || strcasecmp(", hey", tmp_msg
) == 0 ||
759 strcasecmp(": hi", tmp_msg
) == 0 || strcasecmp(": hello", tmp_msg
) == 0 || strcasecmp(": hey", tmp_msg
) == 0)
761 irc_send_message(irc_conn
, NULL
,
762 "Hi %s. My name is %s and I'm here to offer additional services to you! "
763 "Try \"?? help\" for general information and \"?? vomak\" for information about me.",
764 get_nickname(line
, len
), config
->nickname
);
766 else if (strncasecmp("thanks", content
, 6) == 0 || strncasecmp("thx", content
, 3) == 0 ||
767 strcasecmp(", thanks", tmp_msg
) == 0 || strcasecmp(", thx", tmp_msg
) == 0 ||
768 strcasecmp(": thanks", tmp_msg
) == 0 || strcasecmp(": thx", tmp_msg
) == 0)
770 irc_send_message(irc_conn
, get_nickname(line
, len
),
771 "no problem. It was a pleasure to serve you.");
775 else if (strncmp(content
, "?? ", 3) == 0)
777 help_system_query(content
);
779 // pass to process_command() to process other commands (!beer, !test, !learn, ...)
780 else if (*content
== '!')
782 process_command(irc_conn
, line
, len
, content
);
790 * Please note that this will not work on Networks without ChanServ, e.g. on
791 * Quakenet or IRCnet. Your Bot has to be registered with NickServ and to be
792 * added to the channel access list for this to work.
794 static gboolean
irc_toggle_op(irc_conn_t
*irc_conn
, gboolean request_op
)
797 static gchar msg
[1024];
800 if (irc_is_user_op(irc_conn
, "ChanServ"))
802 cmd
= (request_op
) ? "op" : "deop";
803 msg_len
= g_snprintf(msg
, sizeof msg
, "PRIVMSG ChanServ :%s #%s\r\n", cmd
, config
->channel
);
804 irc_send(irc_conn
, msg
, msg_len
);
808 return FALSE
; /* it seems we don't have a ChanServ bot */
812 static gboolean
irc_is_user_op(irc_conn_t
*irc_conn
, const gchar
*nickname
)
815 const gchar
*userlist
;
817 if (nickname
== NULL
)
820 userlist
= get_user_list();
822 if ( (pos
= strstr(userlist
, nickname
)) )
824 if ( (pos
- 1) >= userlist
&& (*(pos
- 1) == '@') )
832 irc_send_message(irc_conn
, NULL
,
833 "Hey. There are crazy things going on here. (O.o)");
835 syslog(LOG_WARNING
, "user %s not found in names list of #%s", nickname
, config
->channel
);
843 static void irc_kick(irc_conn_t
*irc_conn
, const gchar
*nickname
)
845 static gchar msg
[1024];
846 gboolean need_deop
= FALSE
;
851 if (! irc_is_user_op(irc_conn
, config
->nickname
))
853 // if irc_toggle_op fails, most probably we don't have a ChanServ and at this point we
854 // know we are not an op, so fail silently and don't try to kick
855 if (! irc_toggle_op(irc_conn
, TRUE
)) /// TODO: prüfen, ob das auch erfolreich war
860 // give the server a chance to set the op status for us before we make us of it,
861 // and let the victim read his *bang* message
864 msg_len
= g_snprintf(msg
, sizeof msg
, "KICK #%s %s\r\n", config
->channel
, nickname
);
865 irc_send(irc_conn
, msg
, msg_len
);
867 irc_toggle_op(irc_conn
, FALSE
);
871 static gboolean
input_cb(GIOChannel
*source
, GIOCondition cond
, gpointer data
)
876 irc_conn_t
*irc
= data
;
879 if (cond
& (G_IO_ERR
| G_IO_HUP
))
882 if ((buf_len
= socket_fd_gets(irc
->socket
, buf
, sizeof(buf
))) != -1)
884 ret
= process_line(irc
, buf
, buf_len
);
888 irc_conn_t
*irc
= data
;
890 if (cond
& (G_IO_IN
| G_IO_PRI
))
898 rv
= g_io_channel_read_line(source
, &buf
, &buf_len
, NULL
, &err
);
902 buf
[buf_len
] = '\0'; // skip trailing \r\n
904 process_line(irc
, buf
, buf_len
);
909 debug("%s: error: %s", __func__
, err
->message
);
914 while (rv
== G_IO_STATUS_NORMAL
|| rv
== G_IO_STATUS_AGAIN
);
915 debug("%s: status %d\n", __func__
, rv
);
922 void irc_send_message(irc_conn_t
*irc_conn
, const gchar
*target
, const gchar
*format
, ...)
924 static gchar tmp_msg
[1024];
925 static gchar msg
[1024];
929 va_start(ap
, format
);
930 g_vsnprintf(tmp_msg
, sizeof tmp_msg
, format
, ap
);
934 msg_len
= g_snprintf(msg
, sizeof msg
, "PRIVMSG #%s :%s, %s\r\n", config
->channel
, target
, tmp_msg
);
936 msg_len
= g_snprintf(msg
, sizeof msg
, "PRIVMSG #%s :%s\r\n", config
->channel
, tmp_msg
);
938 irc_send(irc_conn
, msg
, msg_len
);
943 * target should not be NULL!
945 void irc_send_notice(irc_conn_t
*irc_conn
, const gchar
*target
, const gchar
*format
, ...)
947 static gchar tmp_msg
[1024];
948 static gchar msg
[1024];
952 va_start(ap
, format
);
953 g_vsnprintf(tmp_msg
, sizeof tmp_msg
, format
, ap
);
956 msg_len
= g_snprintf(msg
, sizeof msg
, "NOTICE #%s :%s, %s\r\n", config
->channel
, target
, tmp_msg
);
958 irc_send(irc_conn
, msg
, msg_len
);
962 // simple wrapper for send() to enable logging for sent commands
963 gint
irc_send(irc_conn_t
*irc_conn
, const gchar
*msg
, guint msg_len
)
965 irc_log(irc_conn
, msg
, TRUE
);
966 return send(irc_conn
->socket
, msg
, msg_len
, MSG_NOSIGNAL
);
970 void irc_goodbye(irc_conn_t
*irc
)
975 if (NZV(irc
->quit_msg
))
976 len
= g_snprintf(msg
, sizeof msg
, "QUIT :%s\r\n", irc
->quit_msg
);
978 len
= g_strlcpy(msg
, "QUIT :Good bye. It was a pleasure to serve you\r\n", sizeof msg
);
979 irc_send(irc
, msg
, len
);
983 void irc_logfile_reopen(irc_conn_t
*irc_conn
)
987 if (irc_conn
->log_fd
!= NULL
)
988 fclose(irc_conn
->log_fd
);
990 if (NZV(config
->logfile
))
992 irc_conn
->log_fd
= g_fopen(config
->logfile
, "a");
993 if (! irc_conn
->log_fd
)
994 vomak_warning("Logfile could not be opened.");
999 gint
irc_finalize(irc_conn_t
*irc_conn
)
1001 if (irc_conn
->socket
< 0)
1004 if (irc_conn
->lock_tag
> 0)
1005 g_source_remove(irc_conn
->lock_tag
);
1007 if (irc_conn
->log_fd
!= NULL
)
1009 irc_log(irc_conn
, "Stop logging\r\n", FALSE
);
1010 fclose(irc_conn
->log_fd
);
1013 if (irc_conn
->read_ioc
)
1015 g_io_channel_shutdown(irc_conn
->read_ioc
, TRUE
, NULL
);
1016 g_io_channel_unref(irc_conn
->read_ioc
);
1017 irc_conn
->read_ioc
= NULL
;
1019 socket_fd_close(irc_conn
->socket
);
1020 irc_conn
->socket
= -1;
1022 g_free(irc_conn
->quit_msg
);
1028 void irc_connect(irc_conn_t
*irc_conn
)
1031 struct sockaddr_in their_addr
;
1037 // Connect the socket to the server
1038 if ((he
= gethostbyname(config
->server
)) == NULL
)
1040 perror("gethostbyname");
1044 if ((irc_conn
->socket
= socket(PF_INET
, SOCK_STREAM
, 0)) == -1)
1050 their_addr
.sin_family
= PF_INET
;
1051 their_addr
.sin_port
= htons(6667);
1052 their_addr
.sin_addr
= *((struct in_addr
*)he
->h_addr_list
[0]);
1053 memset(&(their_addr
.sin_zero
), '\0', 8);
1055 if (connect(irc_conn
->socket
, (struct sockaddr
*)&their_addr
, sizeof(struct sockaddr
)) == -1)
1061 if (NZV(config
->logfile
))
1063 irc_conn
->log_fd
= g_fopen(config
->logfile
, "a");
1064 if (irc_conn
->log_fd
)
1065 irc_log(irc_conn
, "Start logging\r\n", FALSE
);
1067 vomak_warning("Logfile could not be opened.");
1070 msg_len
= g_snprintf(msg
, sizeof(msg
), "USER %s %s %s :%s\r\n",
1071 config
->username
, config
->servername
, config
->servername
, config
->realname
);
1072 if (irc_send(irc_conn
, msg
, msg_len
) == -1)
1074 perror("send USER");
1076 // and how we are called
1077 msg_len
= g_snprintf(msg
, sizeof(msg
), "NICK %s\r\n", config
->nickname
);
1078 if (irc_send(irc_conn
, msg
, msg_len
) == -1)
1080 perror("send NICK");
1082 // identify our nick
1083 if (NZV(config
->nickserv_password
))
1085 msg_len
= g_snprintf(msg
, sizeof(msg
), "PRIVMSG nickserv :identify %s\r\n", config
->nickserv_password
);
1086 // don't use irc_send() here, no need to log our password
1087 if (send(irc_conn
->socket
, msg
, msg_len
, MSG_NOSIGNAL
) == -1)
1089 perror("send NICKSERV");
1093 msg_len
= g_snprintf(msg
, sizeof msg
, "JOIN #%s\r\n", config
->channel
);
1094 if (irc_send(irc_conn
, msg
, msg_len
) == -1)
1099 // input callback, attached to the main loop
1100 irc_conn
->read_ioc
= g_io_channel_unix_new(irc_conn
->socket
);
1101 //~ g_io_channel_set_flags(irc_conn.read_ioc, G_IO_FLAG_NONBLOCK, NULL);
1102 g_io_channel_set_encoding(irc_conn
->read_ioc
, NULL
, NULL
);
1103 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
);