diff options
-rw-r--r-- | .gitattributes | 3 | ||||
-rw-r--r-- | INSTALL | 7 | ||||
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | acconfig.h | 1 | ||||
-rw-r--r-- | configure.ac | 35 | ||||
-rw-r--r-- | docs/perl.txt | 4 | ||||
-rw-r--r-- | docs/proxy.txt | 12 | ||||
-rw-r--r-- | docs/startup-HOWTO.html | 17 | ||||
-rw-r--r-- | src/core/channels.c | 31 | ||||
-rw-r--r-- | src/core/channels.h | 1 | ||||
-rw-r--r-- | src/core/network.c | 124 | ||||
-rw-r--r-- | src/core/network.h | 10 | ||||
-rw-r--r-- | src/fe-common/core/completion.c | 5 | ||||
-rw-r--r-- | src/fe-common/core/windows-layout.c | 4 | ||||
-rw-r--r-- | src/fe-text/gui-entry.c | 63 | ||||
-rw-r--r-- | src/fe-text/gui-entry.h | 14 | ||||
-rw-r--r-- | src/fe-text/gui-readline.c | 12 | ||||
-rw-r--r-- | src/irc/core/irc-channels-setup.c | 6 | ||||
-rw-r--r-- | src/irc/proxy/listen.c | 128 | ||||
-rw-r--r-- | src/irc/proxy/proxy.h | 1 | ||||
-rw-r--r-- | src/perl/irc/Irc.xs | 1 |
21 files changed, 248 insertions, 237 deletions
diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..e1ae7d9d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# On Windows, some Git clients may normalize all text files' line-endings to +# CRLF, which causes obscure errors when running shell scripts. +*.sh eol=lf @@ -11,7 +11,8 @@ To compile irssi you need: For most people, this should work just fine: - ./configure + ./autogen.sh (for people who just cloned the repository) + ./configure (if this script already exists, skip ./autogen.sh) make su make install (not _really_ required except for perl support) @@ -28,10 +29,6 @@ configure options Build the irssi proxy (see startup-HOWTO). - --disable-ipv6 - - Disable IPv6 support. - --disable-ssl Disable SSL support. @@ -1,3 +1,9 @@ +v0.8.18-head 2016-xx-xx The Irssi team <staff@irssi.org> + * Removed --disable-ipv6 + + irssiproxy can now forward all tags through a single port. + + send channel -botcmds immediately when no mask is specified (#175). + - Correctly store te layout of SAFE channels (#183). + v0.8.18 2016-02-13 The Irssi team <staff@irssi.org> * Modules will now require to define a void MODULENAME ## _abicheck(int *version) @@ -1,5 +1,4 @@ /* misc.. */ -#undef HAVE_IPV6 #undef HAVE_SOCKS_H #undef HAVE_STATIC_PERL #undef HAVE_GMODULE diff --git a/configure.ac b/configure.ac index 5f36a7f0..19635ffd 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(irssi, 0.8.18) +AC_INIT(irssi, 0.8.19-head) AC_CONFIG_SRCDIR([src]) AC_CONFIG_AUX_DIR(build-aux) AC_PREREQ(2.50) @@ -140,15 +140,6 @@ AC_ARG_WITH(perl, fi, want_perl=static) -AC_ARG_ENABLE(ipv6, -[ --disable-ipv6 Disable IPv6 support], - if test x$enableval = xno; then - want_ipv6=no - else - want_ipv6=yes - fi, - want_ipv6=yes) - AC_ARG_ENABLE(dane, [ --enable-dane Enable DANE support], if test x$enableval = xno ; then @@ -577,29 +568,6 @@ COMMON_LIBS="$FE_COMMON_LIBS $COMMON_NOUI_LIBS" AC_SUBST(COMMON_NOUI_LIBS) AC_SUBST(COMMON_LIBS) -dnl ** -dnl ** IPv6 support -dnl ** - -have_ipv6=no -if test "x$want_ipv6" = "xyes"; then - AC_MSG_CHECKING([for IPv6]) - AC_CACHE_VAL(irssi_cv_type_in6_addr, - [AC_TRY_COMPILE([ - #include <sys/types.h> - #include <sys/socket.h> - #include <netinet/in.h> - #include <netdb.h> - #include <arpa/inet.h>], - [struct in6_addr i = in6addr_any; return &i == &i;], - have_ipv6=yes, - )]) - if test $have_ipv6 = yes; then - AC_DEFINE(HAVE_IPV6) - fi - AC_MSG_RESULT($have_ipv6) -fi - have_dane=no if test "x$want_dane" = "xyes"; then AC_MSG_CHECKING([for DANE]) @@ -742,7 +710,6 @@ echo "Install prefix ................... : $prefix" echo -echo "Building with IPv6 support ....... : $have_ipv6" echo "Building with SSL support ........ : $have_openssl" if test "x$have_openssl" = "xno" -a "x$enable_ssl" = "xyes"; then if test -f /etc/debian_version; then diff --git a/docs/perl.txt b/docs/perl.txt index 9688341f..59f65462 100644 --- a/docs/perl.txt +++ b/docs/perl.txt @@ -1193,3 +1193,7 @@ Client->{} -------------------- * Calling die in 'script error' handler causes segfault (#101) * Storing and later using any Irssi object may result in use-after-free related crash + - Workaround: always acquire fresh objects +* Calling $dcc->close from the "dcc created" signal will cause unstable behaviour and crashes (#386) + - Workaround: use "dcc request" signal instead AND call + &Irssi::signal_continue(@_); as the first thing diff --git a/docs/proxy.txt b/docs/proxy.txt index e6360a82..224d24e3 100644 --- a/docs/proxy.txt +++ b/docs/proxy.txt @@ -30,6 +30,18 @@ There we have 3 different irc networks answering in 3 ports. Note that you'll have to make the correct /IRCNET ADD and /SERVER ADD commands to make it work properly. +The special network name "?" allows the client to select the network +dynamically on connect: + + /SET irssiproxy_ports ?=2777 + +Now the client can send <network>:<password> as the server password, e.g. + + /CONNECT ... 2777 efnet:secret + +to connect to efnet. If there is no irssiproxy_password set, you can +omit the ":" and just send the network name as the password. + By default, the proxy binds to all available interfaces. To make it only listen on (for example) the loopback address: diff --git a/docs/startup-HOWTO.html b/docs/startup-HOWTO.html index 12128c59..07a9f47c 100644 --- a/docs/startup-HOWTO.html +++ b/docs/startup-HOWTO.html @@ -497,6 +497,13 @@ <pre><code> /SET irssiproxy_ports *=2777 </code></pre> +<p>The special network name <code>?</code> allows the client to select the +network dynamically on connect (see below):</p> + +<pre> +/SET irssiproxy_ports ?=2777 +</pre> + <p>Usage in client side:</p> <p>Just connect to the irssi proxy like it is a normal server with password specified in <code>/SET irssiproxy_password</code>. For example:</p> @@ -505,6 +512,16 @@ /SERVER ADD -network efnet my.irssi-proxy.org 2778 secret </code></pre> +<p>Or, if you used <code>?</code> in <code>irssiproxy_ports</code>:</p> + +<pre> +/SERVER ADD -network IRCnet my.irssi-proxy.org 2777 IRCnet:secret +/SERVER ADD -network efnet my.irssi-proxy.org 2777 efnet:secret +</pre> + +<p>I.e. the network to connect to is specified as part of the password, +separated by <code>:</code> from the actual proxy password.</p> + <p>Irssi proxy works fine with other IRC clients as well.</p> <p><strong>SOCKS</strong></p> diff --git a/src/core/channels.c b/src/core/channels.c index 9af8b844..9c3b92ba 100644 --- a/src/core/channels.c +++ b/src/core/channels.c @@ -233,23 +233,46 @@ static int match_nick_flags(SERVER_REC *server, NICK_REC *nick, char flag) void channel_send_autocommands(CHANNEL_REC *channel) { CHANNEL_SETUP_REC *rec; - NICK_REC *nick; - char **bots, **bot; g_return_if_fail(IS_CHANNEL(channel)); if (channel->session_rejoin) - return; + return; rec = channel_setup_find(channel->name, channel->server->connrec->chatnet); if (rec == NULL || rec->autosendcmd == NULL || !*rec->autosendcmd) return; + /* if the autosendcmd alone (with no -bots parameter) has been + * specified then send it right after joining the channel, when + * the WHO list hasn't been yet retrieved. + * Depending on the value of the 'channel_max_who_sync' option + * the WHO list might not be retrieved after the join event. */ + if (rec->botmasks == NULL || !*rec->botmasks) { /* just send the command. */ eval_special_string(rec->autosendcmd, "", channel->server, channel); - return; } +} + +void channel_send_botcommands(CHANNEL_REC *channel) +{ + CHANNEL_SETUP_REC *rec; + NICK_REC *nick; + char **bots, **bot; + + g_return_if_fail(IS_CHANNEL(channel)); + + if (channel->session_rejoin) + return; + + rec = channel_setup_find(channel->name, channel->server->connrec->chatnet); + if (rec == NULL || rec->autosendcmd == NULL || !*rec->autosendcmd) + return; + + /* this case has already been handled by channel_send_autocommands */ + if (rec->botmasks == NULL || !*rec->botmasks) + return; /* find first available bot.. */ bots = g_strsplit(rec->botmasks, " ", -1); diff --git a/src/core/channels.h b/src/core/channels.h index 0839d69b..bd136fe2 100644 --- a/src/core/channels.h +++ b/src/core/channels.h @@ -31,6 +31,7 @@ void channel_change_visible_name(CHANNEL_REC *channel, const char *name); /* Send the auto send command to channel */ void channel_send_autocommands(CHANNEL_REC *channel); +void channel_send_botcommands(CHANNEL_REC *channel); void channels_init(void); void channels_deinit(void); diff --git a/src/core/network.c b/src/core/network.c index 0751aa95..76659f3e 100644 --- a/src/core/network.c +++ b/src/core/network.c @@ -30,17 +30,11 @@ union sockaddr_union { struct sockaddr sa; struct sockaddr_in sin; -#ifdef HAVE_IPV6 struct sockaddr_in6 sin6; -#endif }; -#ifdef HAVE_IPV6 -# define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \ +#define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \ sizeof(so.sin6) : sizeof(so.sin)) -#else -# define SIZEOF_SOCKADDR(so) (sizeof(so.sin)) -#endif GIOChannel *g_io_channel_new(int handle) { @@ -56,7 +50,7 @@ GIOChannel *g_io_channel_new(int handle) IPADDR ip4_any = { AF_INET, -#if defined(HAVE_IPV6) && defined(IN6ADDR_ANY_INIT) +#if defined(IN6ADDR_ANY_INIT) IN6ADDR_ANY_INIT #else { INADDR_ANY } @@ -68,10 +62,8 @@ int net_ip_compare(IPADDR *ip1, IPADDR *ip2) if (ip1->family != ip2->family) return 0; -#ifdef HAVE_IPV6 if (ip1->family == AF_INET6) return memcmp(&ip1->ip, &ip2->ip, sizeof(ip1->ip)) == 0; -#endif return memcmp(&ip1->ip, &ip2->ip, 4) == 0; } @@ -80,22 +72,16 @@ int net_ip_compare(IPADDR *ip1, IPADDR *ip2) static void sin_set_ip(union sockaddr_union *so, const IPADDR *ip) { if (ip == NULL) { -#ifdef HAVE_IPV6 so->sin6.sin6_family = AF_INET6; so->sin6.sin6_addr = in6addr_any; -#else - so->sin.sin_family = AF_INET; - so->sin.sin_addr.s_addr = INADDR_ANY; -#endif return; } so->sin.sin_family = ip->family; -#ifdef HAVE_IPV6 + if (ip->family == AF_INET6) memcpy(&so->sin6.sin6_addr, &ip->ip, sizeof(ip->ip)); else -#endif memcpy(&so->sin.sin_addr, &ip->ip, 4); } @@ -103,31 +89,25 @@ void sin_get_ip(const union sockaddr_union *so, IPADDR *ip) { ip->family = so->sin.sin_family; -#ifdef HAVE_IPV6 if (ip->family == AF_INET6) memcpy(&ip->ip, &so->sin6.sin6_addr, sizeof(ip->ip)); else -#endif memcpy(&ip->ip, &so->sin.sin_addr, 4); } static void sin_set_port(union sockaddr_union *so, int port) { -#ifdef HAVE_IPV6 if (so->sin.sin_family == AF_INET6) so->sin6.sin6_port = htons((unsigned short)port); else -#endif so->sin.sin_port = htons((unsigned short)port); } static int sin_get_port(union sockaddr_union *so) { -#ifdef HAVE_IPV6 - if (so->sin.sin_family == AF_INET6) - return ntohs(so->sin6.sin6_port); -#endif - return ntohs(so->sin.sin_port); + return ntohs((so->sin.sin_family == AF_INET6) ? + so->sin6.sin6_port : + so->sin.sin_port); } /* Connect to socket */ @@ -272,7 +252,7 @@ GIOChannel *net_listen(IPADDR *my_ip, int *port) /* create the socket */ handle = socket(so.sin.sin_family, SOCK_STREAM, 0); -#ifdef HAVE_IPV6 + if (handle == -1 && (errno == EINVAL || errno == EAFNOSUPPORT)) { /* IPv6 is not supported by OS */ so.sin.sin_family = AF_INET; @@ -280,7 +260,7 @@ GIOChannel *net_listen(IPADDR *my_ip, int *port) handle = socket(AF_INET, SOCK_STREAM, 0); } -#endif + if (handle == -1) return NULL; @@ -399,23 +379,18 @@ int net_getsockname(GIOChannel *handle, IPADDR *addr, int *port) Returns 0 = ok, others = error code for net_gethosterror() */ int net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6) { -#ifdef HAVE_IPV6 union sockaddr_union *so; struct addrinfo hints, *ai, *ailist; int ret, count_v4, count_v6, use_v4, use_v6; -#else - struct hostent *hp; - int count; -#endif g_return_val_if_fail(addr != NULL, -1); memset(ip4, 0, sizeof(IPADDR)); memset(ip6, 0, sizeof(IPADDR)); -#ifdef HAVE_IPV6 memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; /* save error to host_error for later use */ ret = getaddrinfo(addr, NULL, &hints, &ailist); @@ -454,85 +429,40 @@ int net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6) } freeaddrinfo(ailist); return 0; -#else - hp = gethostbyname(addr); - if (hp == NULL) - return h_errno; - - /* count IPs */ - count = 0; - while (hp->h_addr_list[count] != NULL) - count++; - - if (count == 0) - return HOST_NOT_FOUND; /* shouldn't happen? */ - - /* if there are multiple addresses, return random one */ - ip4->family = AF_INET; - memcpy(&ip4->ip, hp->h_addr_list[rand() % count], 4); - - return 0; -#endif } /* Get name for host, *name should be g_free()'d unless it's NULL. Return values are the same as with net_gethostbyname() */ int net_gethostbyaddr(IPADDR *ip, char **name) { -#ifdef HAVE_IPV6 union sockaddr_union so; int host_error; char hostname[NI_MAXHOST]; -#else - struct hostent *hp; -#endif g_return_val_if_fail(ip != NULL, -1); g_return_val_if_fail(name != NULL, -1); *name = NULL; -#ifdef HAVE_IPV6 + memset(&so, 0, sizeof(so)); sin_set_ip(&so, ip); /* save error to host_error for later use */ - host_error = getnameinfo((struct sockaddr *) &so, sizeof(so), - hostname, sizeof(hostname), NULL, 0, 0); + host_error = getnameinfo((struct sockaddr *)&so, sizeof(so), + hostname, sizeof(hostname), + NULL, 0, + NI_NAMEREQD); if (host_error != 0) return host_error; *name = g_strdup(hostname); -#else - if (ip->family != AF_INET) return -1; - hp = gethostbyaddr((const char *) &ip->ip, 4, AF_INET); - if (hp == NULL) return -1; - - *name = g_strdup(hp->h_name); -#endif return 0; } int net_ip2host(IPADDR *ip, char *host) { -#ifdef HAVE_IPV6 - if (!inet_ntop(ip->family, &ip->ip, host, MAX_IP_LEN)) - return -1; -#else - unsigned long ip4; - - if (ip->family != AF_INET) { - strcpy(host, "0.0.0.0"); - } else { - ip4 = ntohl(ip->ip.s_addr); - g_snprintf(host, MAX_IP_LEN, "%lu.%lu.%lu.%lu", - (ip4 & 0xff000000UL) >> 24, - (ip4 & 0x00ff0000) >> 16, - (ip4 & 0x0000ff00) >> 8, - (ip4 & 0x000000ff)); - } -#endif - return 0; + return inet_ntop(ip->family, &ip->ip, host, MAX_IP_LEN) ? 0 : -1; } int net_host2ip(const char *host, IPADDR *ip) @@ -542,12 +472,8 @@ int net_host2ip(const char *host, IPADDR *ip) if (strchr(host, ':') != NULL) { /* IPv6 */ ip->family = AF_INET6; -#ifdef HAVE_IPV6 if (inet_pton(AF_INET6, host, &ip->ip) == 0) return -1; -#else - ip->ip.s_addr = 0; -#endif } else { /* IPv4 */ ip->family = AF_INET; @@ -582,40 +508,20 @@ int net_geterror(GIOChannel *handle) /* get error of net_gethostname() */ const char *net_gethosterror(int error) { -#ifdef HAVE_IPV6 g_return_val_if_fail(error != 0, NULL); return gai_strerror(error); -#else - switch (error) { - case HOST_NOT_FOUND: - return "Host not found"; - case NO_ADDRESS: - return "No IP address found for name"; - case NO_RECOVERY: - return "A non-recovable name server error occurred"; - case TRY_AGAIN: - return "A temporary error on an authoritative name server"; - } - - /* unknown error */ - return NULL; -#endif } /* return TRUE if host lookup failed because it didn't exist (ie. not some error with name server) */ int net_hosterror_notfound(int error) { -#ifdef HAVE_IPV6 #ifdef EAI_NODATA /* NODATA is deprecated */ return error != 1 && (error == EAI_NONAME || error == EAI_NODATA); #else return error != 1 && (error == EAI_NONAME); #endif -#else - return error == HOST_NOT_FOUND || error == NO_ADDRESS; -#endif } /* Get name of TCP service */ diff --git a/src/core/network.h b/src/core/network.h index 73ac8dee..fb627b4d 100644 --- a/src/core/network.h +++ b/src/core/network.h @@ -21,19 +21,11 @@ struct _IPADDR { unsigned short family; -#ifdef HAVE_IPV6 struct in6_addr ip; -#else - struct in_addr ip; -#endif }; /* maxmimum string length of IP address */ -#ifdef HAVE_IPV6 -# define MAX_IP_LEN INET6_ADDRSTRLEN -#else -# define MAX_IP_LEN 20 -#endif +#define MAX_IP_LEN INET6_ADDRSTRLEN #define IPADDR_IS_V6(ip) ((ip)->family != AF_INET) diff --git a/src/fe-common/core/completion.c b/src/fe-common/core/completion.c index a4715d23..1e7833a4 100644 --- a/src/fe-common/core/completion.c +++ b/src/fe-common/core/completion.c @@ -217,6 +217,11 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i want_space = TRUE; signal_emit("complete word", 5, &complist, window, word, linestart, &want_space); last_want_space = want_space; + + if (complist != NULL) { + /* Remove all nulls (from the signal) before doing further processing */ + complist = g_list_remove_all(g_list_first(complist), NULL); + } } g_free(linestart); diff --git a/src/fe-common/core/windows-layout.c b/src/fe-common/core/windows-layout.c index 8ebcc12d..ce6b9910 100644 --- a/src/fe-common/core/windows-layout.c +++ b/src/fe-common/core/windows-layout.c @@ -168,12 +168,12 @@ static void sig_layout_save_item(WINDOW_REC *window, WI_ITEM_REC *item, chat_protocol_find_id(item->chat_type); if (proto != NULL) iconfig_node_set_str(subnode, "chat_type", proto->name); - iconfig_node_set_str(subnode, "name", item->visible_name); + iconfig_node_set_str(subnode, "name", item->name); if (item->server != NULL) { iconfig_node_set_str(subnode, "tag", item->server->tag); if (IS_CHANNEL(item)) { - rec = window_bind_add(window, item->server->tag, item->visible_name); + rec = window_bind_add(window, item->server->tag, item->name); if (rec != NULL) rec->sticky = TRUE; } diff --git a/src/fe-text/gui-entry.c b/src/fe-text/gui-entry.c index 306141ec..27778b2b 100644 --- a/src/fe-text/gui-entry.c +++ b/src/fe-text/gui-entry.c @@ -562,7 +562,7 @@ char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry) return buf; } -void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, int update_cutbuffer) +void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, CUTBUFFER_UPDATE_OP update_cutbuffer) { int newpos, size = 0; @@ -573,7 +573,7 @@ void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, int update_cutbuffer) gui_entry_erase(entry, size, update_cutbuffer); } -void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer) +void gui_entry_erase(GUI_ENTRY_REC *entry, int size, CUTBUFFER_UPDATE_OP update_cutbuffer) { size_t w = 0; @@ -582,17 +582,50 @@ void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer) if (size == 0 || entry->pos < size) return; - if (update_cutbuffer) { - /* put erased text to cutbuffer */ - if (entry->cutbuffer_len < size) { - g_free(entry->cutbuffer); - entry->cutbuffer = g_new(unichar, size+1); - } + if (entry->cutbuffer_len == 0) { + update_cutbuffer = CUTBUFFER_UPDATE_REPLACE; + } + int cutbuffer_new_size = entry->cutbuffer_len + size; + unichar *tmpcutbuffer = entry->cutbuffer; + switch (update_cutbuffer) { + case CUTBUFFER_UPDATE_APPEND: + entry->cutbuffer = g_new(unichar, cutbuffer_new_size+1); + memcpy(entry->cutbuffer, tmpcutbuffer, + entry->cutbuffer_len * sizeof(unichar)); + memcpy(entry->cutbuffer + entry->cutbuffer_len * sizeof(unichar), + entry->text + entry->pos - size, size * sizeof(unichar)); + + entry->cutbuffer_len = cutbuffer_new_size; + entry->cutbuffer[cutbuffer_new_size] = '\0'; + g_free(tmpcutbuffer); + break; + + case CUTBUFFER_UPDATE_PREPEND: + entry->cutbuffer = g_new(unichar, cutbuffer_new_size+1); + memcpy(entry->cutbuffer, entry->text + entry->pos - size, + size * sizeof(unichar)); + memcpy(entry->cutbuffer + size, tmpcutbuffer, + entry->cutbuffer_len * sizeof(unichar)); + + entry->cutbuffer_len = cutbuffer_new_size; + entry->cutbuffer[cutbuffer_new_size] = '\0'; + g_free(tmpcutbuffer); + break; - entry->cutbuffer_len = size; - entry->cutbuffer[size] = '\0'; - memcpy(entry->cutbuffer, entry->text + entry->pos - size, - size * sizeof(unichar)); + case CUTBUFFER_UPDATE_REPLACE: + /* put erased text to cutbuffer */ + if (entry->cutbuffer_len < size) { + g_free(entry->cutbuffer); + entry->cutbuffer = g_new(unichar, size+1); + } + + entry->cutbuffer_len = size; + entry->cutbuffer[size] = '\0'; + memcpy(entry->cutbuffer, entry->text + entry->pos - size, size * sizeof(unichar)); + break; + + case CUTBUFFER_UPDATE_NOOP: + break; } if (entry->utf8) @@ -629,7 +662,7 @@ void gui_entry_erase_cell(GUI_ENTRY_REC *entry) gui_entry_draw(entry); } -void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space) +void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op) { int to; @@ -652,7 +685,7 @@ void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space) } if (to > 0) to++; - gui_entry_erase(entry, entry->pos-to, TRUE); + gui_entry_erase(entry, entry->pos-to, CUTBUFFER_UPDATE_REPLACE); } void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space) @@ -678,7 +711,7 @@ void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space) size = to-entry->pos; entry->pos = to; - gui_entry_erase(entry, size, TRUE); + gui_entry_erase(entry, size, CUTBUFFER_UPDATE_REPLACE); } void gui_entry_transpose_chars(GUI_ENTRY_REC *entry) diff --git a/src/fe-text/gui-entry.h b/src/fe-text/gui-entry.h index 29d8dea2..d22a7fb8 100644 --- a/src/fe-text/gui-entry.h +++ b/src/fe-text/gui-entry.h @@ -20,6 +20,13 @@ typedef struct { unsigned int utf8:1; } GUI_ENTRY_REC; +typedef enum { + CUTBUFFER_UPDATE_NOOP, + CUTBUFFER_UPDATE_REPLACE, + CUTBUFFER_UPDATE_APPEND, + CUTBUFFER_UPDATE_PREPEND +} CUTBUFFER_UPDATE_OP; + extern GUI_ENTRY_REC *active_entry; GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8); @@ -40,10 +47,10 @@ void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str); void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr); char *gui_entry_get_cutbuffer(GUI_ENTRY_REC *entry); -void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, int update_cutbuffer); -void gui_entry_erase(GUI_ENTRY_REC *entry, int size, int update_cutbuffer); +void gui_entry_erase_to(GUI_ENTRY_REC *entry, int pos, CUTBUFFER_UPDATE_OP update_cutbuffer); +void gui_entry_erase(GUI_ENTRY_REC *entry, int size, CUTBUFFER_UPDATE_OP update_cutbuffer); void gui_entry_erase_cell(GUI_ENTRY_REC *entry); -void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space); +void gui_entry_erase_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPDATE_OP cutbuffer_op); void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space); void gui_entry_transpose_chars(GUI_ENTRY_REC *entry); @@ -60,4 +67,5 @@ void gui_entry_move_words(GUI_ENTRY_REC *entry, int count, int to_space); void gui_entry_redraw(GUI_ENTRY_REC *entry); + #endif diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c index 5acfaf60..0dd17394 100644 --- a/src/fe-text/gui-readline.c +++ b/src/fe-text/gui-readline.c @@ -547,7 +547,7 @@ static void key_forward_to_space(void) static void key_erase_line(void) { gui_entry_set_pos(active_entry, active_entry->text_len); - gui_entry_erase(active_entry, active_entry->text_len, TRUE); + gui_entry_erase(active_entry, active_entry->text_len, CUTBUFFER_UPDATE_REPLACE); } static void key_erase_to_beg_of_line(void) @@ -555,7 +555,7 @@ static void key_erase_to_beg_of_line(void) int pos; pos = gui_entry_get_pos(active_entry); - gui_entry_erase(active_entry, pos, TRUE); + gui_entry_erase(active_entry, pos, CUTBUFFER_UPDATE_REPLACE); } static void key_erase_to_end_of_line(void) @@ -564,7 +564,7 @@ static void key_erase_to_end_of_line(void) pos = gui_entry_get_pos(active_entry); gui_entry_set_pos(active_entry, active_entry->text_len); - gui_entry_erase(active_entry, active_entry->text_len - pos, TRUE); + gui_entry_erase(active_entry, active_entry->text_len - pos, CUTBUFFER_UPDATE_REPLACE); } static void key_yank_from_cutbuffer(void) @@ -611,12 +611,12 @@ static void key_delete_character(void) static void key_backspace(void) { - gui_entry_erase(active_entry, 1, FALSE); + gui_entry_erase(active_entry, 1, CUTBUFFER_UPDATE_NOOP); } static void key_delete_previous_word(void) { - gui_entry_erase_word(active_entry, FALSE); + gui_entry_erase_word(active_entry, FALSE, CUTBUFFER_UPDATE_REPLACE); } static void key_delete_next_word(void) @@ -626,7 +626,7 @@ static void key_delete_next_word(void) static void key_delete_to_previous_space(void) { - gui_entry_erase_word(active_entry, TRUE); + gui_entry_erase_word(active_entry, TRUE, CUTBUFFER_UPDATE_REPLACE); } static void key_delete_to_next_space(void) diff --git a/src/irc/core/irc-channels-setup.c b/src/irc/core/irc-channels-setup.c index 2320352d..bbbc095c 100644 --- a/src/irc/core/irc-channels-setup.c +++ b/src/irc/core/irc-channels-setup.c @@ -24,10 +24,12 @@ void irc_channels_setup_init(void) { - signal_add("channel wholist", (SIGNAL_FUNC) channel_send_autocommands); + signal_add("channel wholist", (SIGNAL_FUNC) channel_send_botcommands); + signal_add("channel joined", (SIGNAL_FUNC) channel_send_autocommands); } void irc_channels_setup_deinit(void) { - signal_remove("channel wholist", (SIGNAL_FUNC) channel_send_autocommands); + signal_remove("channel wholist", (SIGNAL_FUNC) channel_send_botcommands); + signal_remove("channel joined", (SIGNAL_FUNC) channel_send_autocommands); } diff --git a/src/irc/proxy/listen.c b/src/irc/proxy/listen.c index 5dc9a704..ef288201 100644 --- a/src/irc/proxy/listen.c +++ b/src/irc/proxy/listen.c @@ -48,7 +48,7 @@ static void remove_client(CLIENT_REC *rec) signal_emit("proxy client disconnected", 1, rec); printtext(rec->server, NULL, MSGLEVEL_CLIENTNOTICE, - "Proxy: Client %s:%d disconnected", rec->host, rec->port); + "Proxy: Client %s:%d disconnected", rec->host, rec->port); g_free(rec->proxy_address); net_sendbuffer_destroy(rec->handle, TRUE); @@ -59,7 +59,7 @@ static void remove_client(CLIENT_REC *rec) } static void proxy_redirect_event(CLIENT_REC *client, const char *command, - int count, const char *arg, int remote) + int count, const char *arg, int remote) { char *str; @@ -67,7 +67,7 @@ static void proxy_redirect_event(CLIENT_REC *client, const char *command, str = g_strdup_printf("proxy %p", client); server_redirect_event(client->server, command, count, - arg, remote, NULL, "", str, NULL); + arg, remote, NULL, "", str, NULL); g_free(str); } @@ -94,28 +94,58 @@ static void grab_who(CLIENT_REC *client, const char *channel) } proxy_redirect_event(client, "who", - client->server->one_endofwho ? 1 : count, - arg->str, -1); + client->server->one_endofwho ? 1 : count, + arg->str, -1); g_strfreev(list); g_string_free(arg, TRUE); } static void handle_client_connect_cmd(CLIENT_REC *client, - const char *cmd, const char *args) + const char *cmd, const char *args) { const char *password; password = settings_get_str("irssiproxy_password"); - if (password != NULL && g_strcmp0(cmd, "PASS") == 0) { - if (g_strcmp0(password, args) == 0) - client->pass_sent = TRUE; - else { + if (g_strcmp0(cmd, "PASS") == 0) { + const char *args_pass; + + if (!client->multiplex) { + args_pass = args; + } else { + IRC_SERVER_REC *server; + char *tag; + const char *tag_end; + + if ((tag_end = strchr(args, ':')) != NULL) { + args_pass = tag_end + 1; + } else { + tag_end = args + strlen(args); + args_pass = ""; + } + + tag = g_strndup(args, tag_end - args); + server = IRC_SERVER(server_find_chatnet(tag)); + g_free(tag); + + if (!server) { + /* an invalid network was specified */ + remove_client(client); + return; + } + + client->server = server; + g_free(client->proxy_address); + client->proxy_address = g_strdup_printf("%.*s.proxy", (int)(tag_end - args), args); + } + + if (g_strcmp0(password, args_pass) != 0) { /* wrong password! */ remove_client(client); - return; + return; } + client->pass_sent = TRUE; } else if (g_strcmp0(cmd, "NICK") == 0) { g_free_not_null(client->nick); client->nick = g_strdup(args); @@ -124,14 +154,14 @@ static void handle_client_connect_cmd(CLIENT_REC *client, } if (client->nick != NULL && client->user_sent) { - if (*password != '\0' && !client->pass_sent) { + if ((*password != '\0' || client->multiplex) && !client->pass_sent) { /* client didn't send us PASS, kill it */ remove_client(client); } else { signal_emit("proxy client connected", 1, client); printtext(client->server, NULL, MSGLEVEL_CLIENTNOTICE, - "Proxy: Client %s:%d connected", - client->host, client->port); + "Proxy: Client %s:%d connected", + client->host, client->port); client->connected = TRUE; proxy_dump_data(client); } @@ -139,7 +169,7 @@ static void handle_client_connect_cmd(CLIENT_REC *client, } static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, - const char *data) + const char *data) { GSList *tmp; if (!client->connected) { @@ -162,8 +192,8 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, g_ascii_strcasecmp(target, client->proxy_address) == 0 || g_ascii_strcasecmp(target, client->nick) == 0) { proxy_outdata(client, ":%s PONG %s :%s\r\n", - client->proxy_address, - client->proxy_address, origin); + client->proxy_address, + client->proxy_address, origin); g_free(params); return; } @@ -174,25 +204,25 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, if (g_ascii_strcasecmp(args, "CTCP ON") == 0) { /* client wants all ctcps */ client->want_ctcp = 1; - for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) { + for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) { CLIENT_REC *rec = tmp->data; - if ((g_ascii_strcasecmp(client->listen->ircnet,rec->listen->ircnet) == 0) && - /* kludgy way to check if the clients aren't the same */ - (client->recv_tag != rec->recv_tag)) { - if (rec->want_ctcp == 1) - proxy_outdata(rec, ":%s NOTICE %s :Another client is now receiving CTCPs sent to %s\r\n", - rec->proxy_address, rec->nick, rec->listen->ircnet); - rec->want_ctcp = 0; - } + if (g_ascii_strcasecmp(client->listen->ircnet, rec->listen->ircnet) == 0 && + /* kludgy way to check if the clients aren't the same */ + client->recv_tag != rec->recv_tag) { + if (rec->want_ctcp == 1) + proxy_outdata(rec, ":%s NOTICE %s :Another client is now receiving CTCPs sent to %s\r\n", + rec->proxy_address, rec->nick, rec->listen->ircnet); + rec->want_ctcp = 0; + } } proxy_outdata(client, ":%s NOTICE %s :You're now receiving CTCPs sent to %s\r\n", - client->proxy_address, client->nick,client->listen->ircnet); + client->proxy_address, client->nick, client->listen->ircnet); } else if (g_ascii_strcasecmp(args, "CTCP OFF") == 0) { - /* client wants proxy to handle all ctcps */ + /* client wants proxy to handle all ctcps */ client->want_ctcp = 0; proxy_outdata(client, ":%s NOTICE %s :Proxy is now handling itself CTCPs sent to %s\r\n", - client->proxy_address, client->nick, client->listen->ircnet); + client->proxy_address, client->nick, client->listen->ircnet); } else { signal_emit("proxy client command", 3, client, args, data); } @@ -201,11 +231,11 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, if (client->server == NULL || !client->server->connected) { proxy_outdata(client, ":%s NOTICE %s :Not connected to server\r\n", - client->proxy_address, client->nick); - return; + client->proxy_address, client->nick); + return; } - /* check if the command could be redirected */ + /* check if the command could be redirected */ if (g_strcmp0(cmd, "WHO") == 0) grab_who(client, args); else if (g_strcmp0(cmd, "WHOWAS") == 0) @@ -263,29 +293,29 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, char *params, *target, *msg; params = event_get_params(args, 2 | PARAM_FLAG_GETREST, - &target, &msg); + &target, &msg); proxy_outserver_all_except(client, "PRIVMSG %s", args); ignore_next = TRUE; if (*msg != '\001' || msg[strlen(msg)-1] != '\001') { signal_emit(server_ischannel(SERVER(client->server), target) ? - "message own_public" : "message own_private", 4, - client->server, msg, target, target); + "message own_public" : "message own_private", 4, + client->server, msg, target, target); } else if (strncmp(msg+1, "ACTION ", 7) == 0) { /* action */ - msg[strlen(msg)-1] = '\0'; + msg[strlen(msg)-1] = '\0'; signal_emit("message irc own_action", 3, - client->server, msg+8, target); + client->server, msg+8, target); } else { - /* CTCP */ + /* CTCP */ char *p; msg[strlen(msg)-1] = '\0'; p = strchr(msg, ' '); - if (p != NULL) *p++ = '\0'; else p = ""; + if (p != NULL) *p++ = '\0'; else p = ""; signal_emit("message irc own_ctcp", 4, - client->server, msg+1, p, target); + client->server, msg+1, p, target); } ignore_next = FALSE; g_free(params); @@ -337,7 +367,7 @@ static void sig_listen(LISTEN_REC *listen) CLIENT_REC *rec; IPADDR ip; NET_SENDBUF_REC *sendbuf; - GIOChannel *handle; + GIOChannel *handle; char host[MAX_IP_LEN]; int port; @@ -352,9 +382,13 @@ static void sig_listen(LISTEN_REC *listen) rec = g_new0(CLIENT_REC, 1); rec->listen = listen; rec->handle = sendbuf; - rec->host = g_strdup(host); + rec->host = g_strdup(host); rec->port = port; - if (g_strcmp0(listen->ircnet, "*") == 0) { + if (g_strcmp0(listen->ircnet, "?") == 0) { + rec->multiplex = TRUE; + rec->proxy_address = g_strdup("multiplex.proxy"); + rec->server = NULL; + } else if (g_strcmp0(listen->ircnet, "*") == 0) { rec->proxy_address = g_strdup("irc.proxy"); rec->server = servers == NULL ? NULL : IRC_SERVER(servers->data); } else { @@ -363,15 +397,15 @@ static void sig_listen(LISTEN_REC *listen) IRC_SERVER(server_find_chatnet(listen->ircnet)); } rec->recv_tag = g_input_add(handle, G_INPUT_READ, - (GInputFunction) sig_listen_client, rec); + (GInputFunction) sig_listen_client, rec); proxy_clients = g_slist_prepend(proxy_clients, rec); - rec->listen->clients = g_slist_prepend(rec->listen->clients, rec); + listen->clients = g_slist_prepend(listen->clients, rec); signal_emit("proxy client connecting", 1, rec); printtext(rec->server, NULL, MSGLEVEL_CLIENTNOTICE, - "Proxy: New client %s:%d on port %d (%s)", - rec->host, rec->port, listen->port, listen->ircnet); + "Proxy: New client %s:%d on port %d (%s)", + rec->host, rec->port, listen->port, listen->ircnet); } static void sig_incoming(IRC_SERVER_REC *server, const char *line) diff --git a/src/irc/proxy/proxy.h b/src/irc/proxy/proxy.h index 158b0675..f37e9c95 100644 --- a/src/irc/proxy/proxy.h +++ b/src/irc/proxy/proxy.h @@ -29,6 +29,7 @@ typedef struct { unsigned int user_sent:1; unsigned int connected:1; unsigned int want_ctcp:1; + unsigned int multiplex:1; } CLIENT_REC; #endif diff --git a/src/perl/irc/Irc.xs b/src/perl/irc/Irc.xs index db5c5f79..4217b4eb 100644 --- a/src/perl/irc/Irc.xs +++ b/src/perl/irc/Irc.xs @@ -157,6 +157,7 @@ static void perl_client_fill_hash(HV *hv, CLIENT_REC *client) (void) hv_store(hv, "user_sent", 9, newSViv(client->user_sent), 0); (void) hv_store(hv, "connected", 9, newSViv(client->connected), 0); (void) hv_store(hv, "want_ctcp", 9, newSViv(client->want_ctcp), 0); + (void) hv_store(hv, "multiplex", 9, newSViv(client->multiplex), 0); (void) hv_store(hv, "ircnet", 6, new_pv(client->listen->ircnet), 0); } |