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
);
67 const goodies_t goodies
[] = {
68 { "!coffee", "A nice sexy waitress brings %s a big cup of coffee!" },
69 { "!coke", "A nice sexy waitress brings %s a cool bottle of coke!" },
70 { "!beer", "A nice sexy waitress brings %s a nice bottle of beer!" },
71 { "!pizza", "Someone calls Mario, and he brings %s a tasty hawaiian pizza!" },
75 gboolean
irc_query_names(gpointer data
)
77 irc_conn_t
*irc
= data
;
78 static gchar msg
[1024];
83 msg_len
= g_snprintf(msg
, sizeof msg
, "NAMES #%s\r\n", config
->channel
);
84 // send the message directly to avoid logging (prevent log file spamming)
85 send(irc
->socket
, msg
, msg_len
, 0);
91 /* 'line' should be terminated by "\r\n" (CRLF) */
92 static void irc_log(irc_conn_t
*irc_conn
, const gchar
*line
, gboolean send
)
96 static gchar str
[256];
99 if (! irc_conn
->log_fd
)
104 strftime(str
, sizeof str
, "%F %T %z ", tp
);
106 log_line
= g_string_new(str
);
107 if (send
) // if we are sending a message, add our ident string
109 g_string_append_printf(log_line
, ":%s!n=%s@%s ",
110 config
->nickname
, config
->username
, config
->servername
);
112 g_string_append(log_line
, line
);
113 /* add \r\n if it is missing */
114 if (strncmp(log_line
->str
+ log_line
->len
- 2, "\r\n", 2) != 0)
116 g_string_append(log_line
, "\r\n");
118 fwrite(log_line
->str
, log_line
->len
, 1, irc_conn
->log_fd
);
119 fflush(irc_conn
->log_fd
);
120 g_string_free(log_line
, TRUE
);
124 static void irc_send_private_message(irc_conn_t
*irc_conn
, const gchar
*target
, const gchar
*format
, ...)
126 static gchar tmp_msg
[1024];
127 static gchar msg
[1024];
134 va_start(ap
, format
);
135 g_vsnprintf(tmp_msg
, sizeof tmp_msg
, format
, ap
);
138 msg_len
= g_snprintf(msg
, sizeof msg
, "PRIVMSG %s :%s, %s\r\n", target
, target
, tmp_msg
);
139 irc_send(irc_conn
, msg
, msg_len
);
143 static gchar
*get_nickname(const gchar
*line
, guint len
)
145 static gchar result
[20];
148 // :eht16!n=enrico@uvena.de PRIVMSG #eht16 :df
149 for (i
= 0; i
< len
; i
++)
151 if (line
[i
] == '!' || line
[i
] == '=' || j
>= 19)
157 result
[j
++] = line
[i
];
165 static gchar
*get_private_message_sender(const gchar
*line
, guint len
)
169 // :eht16!n=enrico@uvena.de PRIVMSG GeanyTestBot :hi
170 for (i
= 0; i
< len
; i
++)
175 if (strncmp("PRIVMSG", line
+ i
+ 1, 7) == 0)
177 static gchar name
[20];
178 g_snprintf(name
, sizeof(name
), "%s :", config
->nickname
);
179 // if the receiver of the message is me, then it's a private message and we return the
180 // sender's nickname, otherwise NULL
181 if (strncmp(name
, line
+ i
+ 9, strlen(config
->nickname
) + 2) == 0)
182 return get_nickname(line
, len
);
192 static gint
get_response(const gchar
*line
, guint len
)
194 static gchar result
[4];
196 gboolean in_response
= FALSE
;
198 // :kornbluth.freenode.net 353 GeanyTestBot @ #eht16 :GeanyTestBot eht16
199 // :kornbluth.freenode.net 366 GeanyTestBot #eht16 :End of /NAMES list.
200 for (i
= 0; i
< len
; i
++)
202 // before a response code
203 if (line
[i
] != ' ' && ! in_response
)
206 // after a response code
207 if (line
[i
] == ' ' && in_response
)
214 i
++; // skip the space
216 result
[j
++] = line
[i
];
225 const gchar
*irc_get_message(const gchar
*line
, guint len
)
227 static gchar result
[1024] = { 0 };
229 gint state
= 0; // represents the current part of the whole line, separated by spaces
231 // :eht16!n=enrico@uvena.de PRIVMSG #eht16 :df foo: var
233 for (i
= 0; i
< len
; i
++)
244 else if (line
[i
] != '\r' && line
[i
] != '\n')
246 result
[j
++] = line
[i
];
255 static const gchar
*irc_get_message_with_name(const gchar
*line
, guint len
, const gchar
*name
)
260 tmp
= irc_get_message(line
, len
);
261 name_len
= strlen(name
);
263 if (strncmp(tmp
, name
, name_len
) == 0)
270 // returns a nickname argument given to cmd, it may also be "cmd for nickname", then the "for" is
272 static const gchar
*get_argument_target(const gchar
*line
, guint len
, const gchar
*cmd
)
274 static gchar result
[20];
278 // :eht16!n=enrico@uvena.de PRIVMSG #eht16 :!beer for me
279 tmp
= irc_get_message(line
, len
);
282 parts
= g_strsplit(tmp
, " ", -1);
283 if (parts
== NULL
|| parts
[0] == NULL
)
289 // if cmd doesn't match, skip it
290 if (parts
[0] != NULL
&& strcmp(parts
[0], cmd
) != 0)
296 if (parts
[1] == NULL
)
302 if (strcmp("for", parts
[1]) == 0)
304 if (parts
[2] != NULL
)
306 if (strcmp(parts
[2], "me") == 0)
309 return NULL
; // if we return NULL, the nickname of the caller is used, aka "me"
312 g_strlcpy(result
, parts
[2], sizeof(result
));
315 g_strlcpy(result
, parts
[1], sizeof(result
));
317 else if (strcmp(parts
[1], "me") == 0)
320 return NULL
; // if we return NULL, the nickname of the caller is used, aka "me"
324 g_strlcpy(result
, parts
[1], sizeof(result
));
332 // Parses the line and puts the first argument in arg1, all further arguments are concatenated
333 // in arg2. arg1 and arg2 should be freed when no longer needed.
334 // If arg1 and arg2 were set successfully, TRUE is returned, if any error occurs, FALSE is returned
335 // and arg1 and arg2 are set to NULL.
336 static gboolean
get_argument_two(const gchar
*line
, guint len
, const gchar
*cmd
,
337 gchar
**arg1
, gchar
**arg2
)
345 // :eht16!n=enrico@uvena.de PRIVMSG #eht16 :!learn keyword text to be added
346 tmp
= irc_get_message(line
, len
);
348 // -> !learn keyword text to be added
349 parts
= g_strsplit(tmp
, " ", 3);
350 if (parts
== NULL
|| parts
[0] == NULL
)
356 // if cmd doesn't match, skip it
357 if (parts
[0] != NULL
&& strcmp(parts
[0], cmd
) != 0)
363 if (parts
[1] == NULL
|| parts
[2] == NULL
)
369 *arg1
= g_strdup(parts
[1]);
370 *arg2
= g_strdup(parts
[2]);
378 static void command_fortune(irc_conn_t
*irc_conn
)
380 GError
*error
= NULL
;
384 if (g_spawn_command_line_sync(config
->fortune_cmd
, &out
, &err
, NULL
, &error
))
386 if (out
!= NULL
&& *out
!= '\0')
388 gchar
**lines
= g_strsplit(out
, "\n", -1);
391 len
= g_strv_length(lines
);
392 for (i
= 0; i
< len
; i
++)
394 if (strlen(g_strchomp(lines
[i
])) > 0)
395 irc_send_message(irc_conn
, NULL
, lines
[i
]);
401 vomak_warning("Executing fortune failed (%s)", err
);
408 vomak_warning("Executing fortune failed (%s)", error
->message
);
414 static void command_moo(irc_conn_t
*irc_conn
)
416 gint32 rand
= g_random_int();
421 const gchar
*moo_str
[] = {
428 "..\"Have you mooed today?\"..\r\n",
432 for (i
= 0; moo_str
[i
] != NULL
; i
++)
434 irc_send_message(irc_conn
, NULL
, moo_str
[i
]);
439 irc_send_message(irc_conn
, NULL
, "I have Super Cow Powers. Have you mooed today?");
444 static void command_learn(irc_conn_t
*irc_conn
, const gchar
*line
, guint len
)
448 if (get_argument_two(line
, len
, "!learn", &arg1
, &arg2
))
450 gint result
= help_system_learn(arg1
, arg2
);
457 text
= g_strdup_printf("new keyword \"%s\" was added.", arg1
);
462 text
= g_strdup_printf("existing keyword \"%s\" was updated.", arg1
);
467 text
= g_strdup("an error occurred. Database not updated.");
471 irc_send_message(irc_conn
, get_nickname(line
, len
), "%s", text
);
478 irc_send_message(irc_conn
, get_nickname(line
, len
),
479 "wrong usage of !learn. Use \"?? learn\" for usage information.");
483 static void command_alias(irc_conn_t
*irc_conn
, const gchar
*line
, guint len
)
487 if (get_argument_two(line
, len
, "!alias", &arg1
, &arg2
))
489 // detect if arg2 has more than one word by scanning for spaces in
491 if (strchr(arg2
, ' '))
493 irc_send_message(irc_conn
, get_nickname(line
, len
),
494 "You gave me more than two arguments for !alias. I can not handle this.");
496 // check if the target actually exist and refuse if it doesn't exist
497 else if (g_hash_table_lookup(config
->data
, arg2
) == NULL
)
499 irc_send_message(irc_conn
, get_nickname(line
, len
),
500 "The given target for the alias does not exist. I will refuse your request.");
506 gchar
*alias
= g_strconcat("@", arg2
, NULL
);
508 result
= help_system_learn(arg1
, alias
);
514 text
= g_strdup_printf("new alias \"%s\" was added.", arg1
);
519 text
= g_strdup_printf("existing alias \"%s\" was updated.", arg1
);
524 text
= g_strdup("An error occurred. Database not updated.");
529 irc_send_message(irc_conn
, get_nickname(line
, len
), "%s", text
);
538 irc_send_message(irc_conn
, get_nickname(line
, len
),
539 "wrong usage of !alias. Use \"?? alias\" for usage information.");
543 static void command_goodies(irc_conn_t
*irc_conn
, const gchar
*line
, guint len
, gint goodie
)
545 const goodies_t
*g
= &goodies
[goodie
];
546 const gchar
*arg
= get_argument_target(line
, len
, g
->command
);
549 arg
= get_nickname(line
, len
);
551 irc_send_message(irc_conn
, NULL
,
556 static void process_command(irc_conn_t
*irc_conn
, const gchar
*line
, guint len
, const gchar
*content
)
559 if (strncmp(content
, "!test", 5) == 0)
561 irc_send_message(irc_conn
, get_nickname(line
, len
), "I don't like tests!");
564 else if (strncmp(content
, "!moo", 4) == 0)
566 command_moo(irc_conn
);
569 else if (config
->fortune_cmd
!= NULL
&& strncmp(content
, "!fortune", 8) == 0)
571 command_fortune(irc_conn
);
574 else if (strncmp(content
, "!coffee", 7) == 0)
576 command_goodies(irc_conn
, line
, len
, GOODIES_COFFEE
);
579 else if (strncmp(content
, "!coke", 5) == 0)
581 command_goodies(irc_conn
, line
, len
, GOODIES_COKE
);
584 else if (strncmp(content
, "!beer", 5) == 0)
586 command_goodies(irc_conn
, line
, len
, GOODIES_BEER
);
589 else if (strncmp(content
, "!pizza", 5) == 0)
591 command_goodies(irc_conn
, line
, len
, GOODIES_PIZZA
);
594 else if (strncmp(content
, "!help", 5) == 0)
596 help_system_query("?? help");
600 * You have to register your bot with nickserv and add it to the access-list
601 * of your channel to make the !roulette-command work.
602 * This is just tested on FreeNode. Please feel free to write patches, that
603 * will make this work on other Networks.
605 else if (strncmp(content
, "!roulette", 9) == 0)
607 gint32 rand
= g_random_int();
608 static gint bullets_left
= 6;
610 if (rand
% 6 == 0 || bullets_left
<= 0)
612 irc_send_message(irc_conn
, NULL
, "*bang*");
613 irc_kick(irc_conn
, get_nickname(line
, len
));
619 irc_send_message(irc_conn
, NULL
, "*click*");
624 /// TODO require op privileges for !learn
625 else if (strncmp(content
, "!learn", 6) == 0)
627 command_learn(irc_conn
, line
, len
);
630 else if (strncmp(content
, "!alias", 6) == 0)
632 command_alias(irc_conn
, line
, len
);
635 else if (strncmp(content
, "?? ", 3) == 0)
637 help_system_query(content
);
642 static gboolean
process_line(irc_conn_t
*irc_conn
, const gchar
*line
, guint len
)
644 static gchar msg
[1024];
646 gint response
= get_response(line
, len
);
647 static gchar tmp_userlist
[1024];
649 const gchar
*content
;
650 static gboolean connected
= FALSE
;
652 content
= irc_get_message(line
, len
);
654 // don't log the NAMES command's output (prevent log file spam)
655 if (response
!= 353 && response
!= 366)
656 irc_log(irc_conn
, line
, FALSE
);
666 // An error occurred, try to quit cleanly and print the error
667 if (response
> 400 && response
< 503)
669 // ignore Freenode's info messages sent with error code 477
670 // (see http://freenode.net/faq.shtml#freenode-info)
671 if (response
!= 477 || strstr(line
, "[freenode-info]") == NULL
)
673 g_print("Error: %s", line
);
675 syslog(LOG_WARNING
, "received error: %d (%s)", response
, g_strstrip((gchar
*) line
));
681 // retrieve user name list
682 else if (response
== 353)
684 if (tmp_userlist
[0] == '\0')
685 g_strlcpy(tmp_userlist
, strchr(content
, ':') + 1, sizeof(tmp_userlist
));
687 g_strlcat(tmp_userlist
, strchr(content
, ':') + 1, sizeof(tmp_userlist
));
689 // retrieve end of user name list
690 else if (response
== 366)
692 if (tmp_userlist
[0] != '\0')
694 set_user_list(tmp_userlist
);
695 tmp_userlist
[0] = '\0';
698 else if (! connected
)
700 // don't do anything else until we got finished connecting (to skip MOTD messages)
703 else if (strncmp("PING :", line
, 6) == 0)
705 msg_len
= g_snprintf(msg
, sizeof msg
, "PONG %s\r\n", line
+ 6); // 7 = "PING :"
706 debug("PONG: -%s-\n", msg
);
707 irc_send(irc_conn
, msg
, msg_len
);
709 // handle private message
710 else if ((priv_sender
= get_private_message_sender(line
, len
)) != NULL
)
712 // to be able to send private messages to users, you need to register your bot's
713 // nickname with Nickserv (at least on Freenode)
714 irc_send_private_message(irc_conn
, priv_sender
, "I don't like private messages!");
716 // Hi /me, acts on "hello $nickname" and "hi $nickname", hi and hello are case-insensitive
718 else if (strstr(content
, config
->nickname
) != NULL
)
720 const gchar
*tmp_msg
= irc_get_message_with_name(line
, len
, config
->nickname
);
722 if (strncasecmp("hi", content
, 2) == 0 || strncasecmp("hello", content
, 5) == 0 || strncasecmp("hey", content
, 3) == 0 ||
723 strcasecmp(", hi", tmp_msg
) == 0 || strcasecmp(", hello", tmp_msg
) == 0 || strcasecmp(", hey", tmp_msg
) == 0 ||
724 strcasecmp(": hi", tmp_msg
) == 0 || strcasecmp(": hello", tmp_msg
) == 0 || strcasecmp(": hey", tmp_msg
) == 0)
726 irc_send_message(irc_conn
, NULL
,
727 "Hi %s. My name is %s and I'm here to offer additional services to you! "
728 "Try \"?? help\" for general information and \"?? vomak\" for information about me.",
729 get_nickname(line
, len
), config
->nickname
);
731 else if (strncasecmp("thanks", content
, 6) == 0 || strncasecmp("thx", content
, 3) == 0 ||
732 strcasecmp(", thanks", tmp_msg
) == 0 || strcasecmp(", thx", tmp_msg
) == 0 ||
733 strcasecmp(": thanks", tmp_msg
) == 0 || strcasecmp(": thx", tmp_msg
) == 0)
735 irc_send_message(irc_conn
, get_nickname(line
, len
),
736 "no problem. It was a pleasure to serve you.");
739 // pass to process_command() to process other commands (!beer, !test, !learn, ...)
742 process_command(irc_conn
, line
, len
, content
);
750 * Please note that this will not work on Networks without ChanServ, e.g. on
751 * Quakenet or IRCnet. Your Bot has to be registered with NickServ and to be
752 * added to the channel access list for this to work.
754 static gboolean
irc_toggle_op(irc_conn_t
*irc_conn
, gboolean request_op
)
757 static gchar msg
[1024];
760 if (irc_is_user_op(irc_conn
, "ChanServ"))
762 cmd
= (request_op
) ? "op" : "deop";
763 msg_len
= g_snprintf(msg
, sizeof msg
, "PRIVMSG ChanServ :%s #%s\r\n", cmd
, config
->channel
);
764 irc_send(irc_conn
, msg
, msg_len
);
768 return FALSE
; /* it seems we don't have a ChanServ bot */
772 static gboolean
irc_is_user_op(irc_conn_t
*irc_conn
, const gchar
*nickname
)
775 const gchar
*userlist
;
777 if (nickname
== NULL
)
780 userlist
= get_user_list();
782 if ( (pos
= strstr(userlist
, nickname
)) )
784 if ( (pos
- 1) >= userlist
&& (*(pos
- 1) == '@') )
792 irc_send_message(irc_conn
, NULL
,
793 "Hey. There are crazy things going on here. (O.o)");
795 syslog(LOG_WARNING
, "user %s not found in names list of #%s", nickname
, config
->channel
);
803 static void irc_kick(irc_conn_t
*irc_conn
, const gchar
*nickname
)
805 static gchar msg
[1024];
806 gboolean need_deop
= FALSE
;
811 if (! irc_is_user_op(irc_conn
, config
->nickname
))
813 // if irc_toggle_op fails, most probably we don't have a ChanServ and at this point we
814 // know we are not an op, so fail silently and don't try to kick
815 if (! irc_toggle_op(irc_conn
, TRUE
)) /// TODO: prüfen, ob das auch erfolreich war
820 // give the server a chance to set the op status for us before we make us of it,
821 // and let the victim read his *bang* message
824 msg_len
= g_snprintf(msg
, sizeof msg
, "KICK #%s %s\r\n", config
->channel
, nickname
);
825 irc_send(irc_conn
, msg
, msg_len
);
827 irc_toggle_op(irc_conn
, FALSE
);
831 static gboolean
input_cb(GIOChannel
*source
, GIOCondition cond
, gpointer data
)
836 irc_conn_t
*irc
= data
;
839 if ((buf_len
= socket_fd_gets(irc
->socket
, buf
, sizeof(buf
))) != -1)
841 ret
= process_line(irc
, buf
, buf_len
);
845 irc_conn_t
*irc
= data
;
847 if (cond
& (G_IO_IN
| G_IO_PRI
))
855 rv
= g_io_channel_read_line(source
, &buf
, &buf_len
, NULL
, &err
);
859 buf
[buf_len
] = '\0'; // skip trailing \r\n
861 process_line(irc
, buf
, buf_len
);
866 debug("%s: error: %s", __func__
, err
->message
);
871 while (rv
== G_IO_STATUS_NORMAL
|| rv
== G_IO_STATUS_AGAIN
);
872 debug("%s: status %d\n", __func__
, rv
);
879 void irc_send_message(irc_conn_t
*irc_conn
, const gchar
*target
, const gchar
*format
, ...)
881 static gchar tmp_msg
[1024];
882 static gchar msg
[1024];
886 va_start(ap
, format
);
887 g_vsnprintf(tmp_msg
, sizeof tmp_msg
, format
, ap
);
891 msg_len
= g_snprintf(msg
, sizeof msg
, "PRIVMSG #%s :%s, %s\r\n", config
->channel
, target
, tmp_msg
);
893 msg_len
= g_snprintf(msg
, sizeof msg
, "PRIVMSG #%s :%s\r\n", config
->channel
, tmp_msg
);
895 irc_send(irc_conn
, msg
, msg_len
);
899 // simple wrapper for send() to enable logging for sent commands
900 gint
irc_send(irc_conn_t
*irc_conn
, const gchar
*msg
, guint msg_len
)
902 irc_log(irc_conn
, msg
, TRUE
);
903 return send(irc_conn
->socket
, msg
, msg_len
, 0);
907 void irc_goodbye(irc_conn_t
*irc
)
912 if (NZV(irc
->quit_msg
))
913 len
= g_snprintf(msg
, sizeof msg
, "QUIT :%s\r\n", irc
->quit_msg
);
915 len
= g_strlcpy(msg
, "QUIT :Good bye. It was a pleasure to serve you\r\n", sizeof msg
);
916 irc_send(irc
, msg
, len
);
920 void irc_logfile_reopen(irc_conn_t
*irc_conn
)
924 if (irc_conn
->log_fd
!= NULL
)
925 fclose(irc_conn
->log_fd
);
927 if (NZV(config
->logfile
))
929 irc_conn
->log_fd
= g_fopen(config
->logfile
, "a");
930 if (! irc_conn
->log_fd
)
931 vomak_warning("Logfile could not be opened.");
936 gint
irc_finalize(irc_conn_t
*irc_conn
)
938 if (irc_conn
->socket
< 0)
941 if (irc_conn
->lock_tag
> 0)
942 g_source_remove(irc_conn
->lock_tag
);
944 if (irc_conn
->log_fd
!= NULL
)
946 irc_log(irc_conn
, "Stop logging\r\n", FALSE
);
947 fclose(irc_conn
->log_fd
);
950 if (irc_conn
->read_ioc
)
952 g_io_channel_shutdown(irc_conn
->read_ioc
, TRUE
, NULL
);
953 g_io_channel_unref(irc_conn
->read_ioc
);
954 irc_conn
->read_ioc
= NULL
;
956 socket_fd_close(irc_conn
->socket
);
957 irc_conn
->socket
= -1;
959 g_free(irc_conn
->quit_msg
);
965 void irc_connect(irc_conn_t
*irc_conn
)
968 struct sockaddr_in their_addr
;
974 // Connect the socket to the server
975 if ((he
= gethostbyname(config
->server
)) == NULL
)
977 perror("gethostbyname");
981 if ((irc_conn
->socket
= socket(PF_INET
, SOCK_STREAM
, 0)) == -1)
987 their_addr
.sin_family
= PF_INET
;
988 their_addr
.sin_port
= htons(6667);
989 their_addr
.sin_addr
= *((struct in_addr
*)he
->h_addr_list
[0]);
990 memset(&(their_addr
.sin_zero
), '\0', 8);
992 if (connect(irc_conn
->socket
, (struct sockaddr
*)&their_addr
, sizeof(struct sockaddr
)) == -1)
998 if (NZV(config
->logfile
))
1000 irc_conn
->log_fd
= g_fopen(config
->logfile
, "a");
1001 if (irc_conn
->log_fd
)
1002 irc_log(irc_conn
, "Start logging\r\n", FALSE
);
1004 vomak_warning("Logfile could not be opened.");
1007 msg_len
= g_snprintf(msg
, sizeof(msg
), "USER %s %s %s :%s\r\n",
1008 config
->username
, config
->servername
, config
->servername
, config
->realname
);
1009 if (irc_send(irc_conn
, msg
, msg_len
) == -1)
1011 perror("send USER");
1013 // and how we are called
1014 msg_len
= g_snprintf(msg
, sizeof(msg
), "NICK %s\r\n", config
->nickname
);
1015 if (irc_send(irc_conn
, msg
, msg_len
) == -1)
1017 perror("send NICK");
1019 // identify our nick
1020 if (NZV(config
->nickserv_password
))
1022 msg_len
= g_snprintf(msg
, sizeof(msg
), "PRIVMSG nickserv :identify %s\r\n", config
->nickserv_password
);
1023 // don't use irc_send() here, no need to log our password
1024 if (send(irc_conn
->socket
, msg
, msg_len
, 0) == -1)
1026 perror("send NICKSERV");
1030 g_snprintf(msg
, sizeof msg
, "JOIN #%s\r\n", config
->channel
);
1031 if (irc_send(irc_conn
, msg
, strlen(msg
)) == -1)
1036 // input callback, attached to the main loop
1037 irc_conn
->read_ioc
= g_io_channel_unix_new(irc_conn
->socket
);
1038 //~ g_io_channel_set_flags(irc_conn.read_ioc, G_IO_FLAG_NONBLOCK, NULL);
1039 g_io_channel_set_encoding(irc_conn
->read_ioc
, NULL
, NULL
);
1040 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
);