diff options
-rwxr-xr-x | autogen.sh | 2 | ||||
-rw-r--r-- | src/common/cfgfiles.c | 12 | ||||
-rw-r--r-- | src/common/cfgfiles.h | 2 | ||||
-rw-r--r-- | src/common/common.vcxproj | 4 | ||||
-rw-r--r-- | src/common/dcc.c | 3 | ||||
-rw-r--r-- | src/common/hexchat.c | 2 | ||||
-rw-r--r-- | src/common/inbound.c | 13 | ||||
-rw-r--r-- | src/common/outbound.c | 6 | ||||
-rw-r--r-- | src/common/plugin.c | 74 | ||||
-rw-r--r-- | src/common/plugin.h | 8 | ||||
-rw-r--r-- | src/common/proto-irc.c | 20 | ||||
-rw-r--r-- | src/common/servlist.c | 12 | ||||
-rw-r--r-- | src/common/text.c | 18 | ||||
-rw-r--r-- | src/common/userlist.c | 4 | ||||
-rw-r--r-- | src/common/util.c | 78 | ||||
-rw-r--r-- | src/common/util.h | 2 | ||||
-rw-r--r-- | src/fe-gtk/fe-gtk.vcxproj | 4 | ||||
-rw-r--r-- | src/fe-gtk/setup.c | 9 | ||||
-rw-r--r-- | src/fe-gtk/xtext.c | 94 | ||||
-rw-r--r-- | src/fe-text/fe-text.c | 2 | ||||
-rw-r--r-- | win32/hexchat.props | 4 | ||||
-rw-r--r-- | win32/installer/hexchat.iss.tt | 137 | ||||
-rw-r--r-- | win32/installer/installer.vcxproj | 4 |
23 files changed, 343 insertions, 171 deletions
diff --git a/autogen.sh b/autogen.sh index 607aa949..324870a3 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh have_automake=false if automake --version < /dev/null > /dev/null 2>&1 ; then diff --git a/src/common/cfgfiles.c b/src/common/cfgfiles.c index 725b9632..7d0e9c91 100644 --- a/src/common/cfgfiles.c +++ b/src/common/cfgfiles.c @@ -41,7 +41,7 @@ #define DEF_FONT "Monospace 9" #define DEF_FONT_ALTER "Arial Unicode MS,Lucida Sans Unicode,MS Gothic,Unifont" -const char const *languages[LANGUAGES_LENGTH] = { +const char * const languages[LANGUAGES_LENGTH] = { "af", "sq", "am", "ast", "az", "eu", "be", "bg", "ca", "zh_CN", /* 0 .. 9 */ "zh_TW", "cs", "da", "nl", "en_GB", "en", "et", "fi", "fr", "gl", /* 10 .. 19 */ "de", "el", "gu", "hi", "hu", "id", "it", "ja", "kn", "rw", /* 20 .. 29 */ @@ -630,7 +630,7 @@ convert_with_fallback (const char *str, const char *fallback) } static int -find_language_number (const char const *lang) +find_language_number (const char * const lang) { int i; @@ -1085,12 +1085,10 @@ set_showval (session *sess, const struct prefs *var, char *tbuf) len = strlen (var->name); memcpy (tbuf, var->name, len); - dots = 29 - len; - - if (dots < 0) - { + if (len > 29) dots = 0; - } + else + dots = 29 - len; tbuf[len++] = '\003'; tbuf[len++] = '2'; diff --git a/src/common/cfgfiles.h b/src/common/cfgfiles.h index 83db9656..79bc0582 100644 --- a/src/common/cfgfiles.h +++ b/src/common/cfgfiles.h @@ -27,7 +27,7 @@ #define LANGUAGES_LENGTH 52 extern char *xdir; -extern const char const *languages[LANGUAGES_LENGTH]; +extern const char * const languages[LANGUAGES_LENGTH]; char *cfg_get_str (char *cfg, const char *var, char *dest, int dest_len); int cfg_get_bool (char *var); diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 13610cee..39c50222 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -159,8 +159,8 @@ <Command> <![CDATA[ SET SOLUTIONDIR=$(SolutionDir)..\ -"%PROGRAMFILES%\Common Files\microsoft shared\TextTemplating\12.0\TextTransform.exe" -out "%SOLUTIONDIR%config-win32.h" "%SOLUTIONDIR%config-win32.h.tt" -"%PROGRAMFILES%\Common Files\microsoft shared\TextTemplating\12.0\TextTransform.exe" -out "%SOLUTIONDIR%win32\version.txt" "%SOLUTIONDIR%win32\version.txt.tt" +$(TextTransformPath) -out "%SOLUTIONDIR%config-win32.h" "%SOLUTIONDIR%config-win32.h.tt" +$(TextTransformPath) -out "%SOLUTIONDIR%win32\version.txt" "%SOLUTIONDIR%win32\version.txt.tt" ]]> </Command> </PreBuildEvent> diff --git a/src/common/dcc.c b/src/common/dcc.c index 57354ba9..ca1be140 100644 --- a/src/common/dcc.c +++ b/src/common/dcc.c @@ -557,8 +557,7 @@ dcc_chat_line (struct DCC *dcc, char *line) for (i = 5; i < PDIWORDS; i++) word[i] = "\000"; - ret = plugin_emit_print (sess, word) - + plugin_emit_print_attrs (sess, word, 0); + ret = plugin_emit_print (sess, word, 0); /* did the plugin close it? */ if (!g_slist_find (dcc_list, dcc)) diff --git a/src/common/hexchat.c b/src/common/hexchat.c index 17309dee..5b23621f 100644 --- a/src/common/hexchat.c +++ b/src/common/hexchat.c @@ -232,7 +232,7 @@ find_channel (server *serv, char *chan) while (list) { sess = list->data; - if ((!serv || serv == sess->server) && sess->type != SESS_DIALOG) + if ((!serv || serv == sess->server) && sess->type == SESS_CHANNEL) { if (!serv->p_cmp (chan, sess->channel)) return sess; diff --git a/src/common/inbound.c b/src/common/inbound.c index b9503ddb..8d51df94 100644 --- a/src/common/inbound.c +++ b/src/common/inbound.c @@ -467,7 +467,7 @@ inbound_chanmsg (server *serv, session *sess, char *chan, char *from, if (fromme) { - if (prefs.hex_away_auto_unmark && serv->is_away) + if (prefs.hex_away_auto_unmark && serv->is_away && !tags_data->timestamp) sess->server->p_set_back (sess->server); EMIT_SIGNAL_TIMESTAMP (XP_TE_UCHANMSG, sess, from, text, nickchar, NULL, 0, tags_data->timestamp); @@ -1439,10 +1439,15 @@ inbound_banlist (session *sess, time_t stamp, char *chan, char *mask, server *serv = sess->server; char *nl; - if ((nl = strchr (time_str, '\n'))) - *nl = 0; - if (stamp == 0) + if (stamp <= 0) + { time_str = ""; + } + else + { + if ((nl = strchr (time_str, '\n'))) + *nl = 0; + } sess = find_channel (serv, chan); if (!sess) diff --git a/src/common/outbound.c b/src/common/outbound.c index 8e412186..96425f8f 100644 --- a/src/common/outbound.c +++ b/src/common/outbound.c @@ -3947,9 +3947,9 @@ const struct commands xc_cmds[] = { N_("INVITE <nick> [<channel>], invites someone to a channel, by default the current channel (needs chanop)")}, {"JOIN", cmd_join, 1, 0, 0, N_("JOIN <channel>, joins the channel")}, {"KICK", cmd_kick, 1, 1, 1, - N_("KICK <nick>, kicks the nick from the current channel (needs chanop)")}, + N_("KICK <nick> [reason], kicks the nick from the current channel (needs chanop)")}, {"KICKBAN", cmd_kickban, 1, 1, 1, - N_("KICKBAN <nick>, bans then kicks the nick from the current channel (needs chanop)")}, + N_("KICKBAN <nick> [reason], bans then kicks the nick from the current channel (needs chanop)")}, {"KILLALL", cmd_killall, 0, 0, 1, "KILLALL, immediately exit"}, {"LAGCHECK", cmd_lagcheck, 0, 0, 1, N_("LAGCHECK, forces a new lag check")}, @@ -3978,7 +3978,7 @@ const struct commands xc_cmds[] = { {"MSG", cmd_msg, 0, 0, 1, N_("MSG <nick> <message>, sends a private message, message \".\" to send to last nick or prefix with \"=\" for dcc chat")}, {"NAMES", cmd_names, 1, 0, 1, - N_("NAMES, Lists the nicks on the current channel")}, + N_("NAMES [channel], Lists the nicks on the channel")}, {"NCTCP", cmd_nctcp, 1, 0, 1, N_("NCTCP <nick> <message>, Sends a CTCP notice")}, {"NEWSERVER", cmd_newserver, 0, 0, 1, N_("NEWSERVER [-noconnect] <hostname> [<port>]")}, diff --git a/src/common/plugin.c b/src/common/plugin.c index 228983f3..ee3b26c8 100644 --- a/src/common/plugin.c +++ b/src/common/plugin.c @@ -102,16 +102,21 @@ enum LIST_USERS }; +/* We use binary flags here because it makes it possible for plugin_hook_find() + * to match several types of hooks. This is used so that plugin_hook_run() + * match both HOOK_SERVER and HOOK_SERVER_ATTRS hooks when plugin_emit_server() + * is called. + */ enum { - HOOK_COMMAND, /* /command */ - HOOK_SERVER, /* PRIVMSG, NOTICE, numerics */ - HOOK_SERVER_ATTRS, /* same as above, with attributes */ - HOOK_PRINT, /* All print events */ - HOOK_PRINT_ATTRS, /* same as above, with attributes */ - HOOK_TIMER, /* timeouts */ - HOOK_FD, /* sockets & fds */ - HOOK_DELETED /* marked for deletion */ + HOOK_COMMAND = 1 << 0, /* /command */ + HOOK_SERVER = 1 << 1, /* PRIVMSG, NOTICE, numerics */ + HOOK_SERVER_ATTRS = 1 << 2, /* same as above, with attributes */ + HOOK_PRINT = 1 << 3, /* All print events */ + HOOK_PRINT_ATTRS = 1 << 4, /* same as above, with attributes */ + HOOK_TIMER = 1 << 5, /* timeouts */ + HOOK_FD = 1 << 6, /* sockets & fds */ + HOOK_DELETED = 1 << 7 /* marked for deletion */ }; GSList *plugin_list = NULL; /* export for plugingui.c */ @@ -560,16 +565,14 @@ plugin_hook_find (GSList *list, int type, char *name) while (list) { hook = list->data; - if (hook && hook->type == type) + if (hook && (hook->type & type)) { if (g_ascii_strcasecmp (hook->name, name) == 0) return list; - if (type == HOOK_SERVER) - { - if (g_ascii_strcasecmp (hook->name, "RAW LINE") == 0) + if ((type & HOOK_SERVER) + && g_ascii_strcasecmp (hook->name, "RAW LINE") == 0) return list; - } } list = list->next; } @@ -599,7 +602,7 @@ plugin_hook_run (session *sess, char *name, char *word[], char *word_eol[], hook->pl->context = sess; /* run the plugin's callback function */ - switch (type) + switch (hook->type) { case HOOK_COMMAND: ret = ((hexchat_cmd_cb *)hook->callback) (word, word_eol, hook->userdata); @@ -676,39 +679,30 @@ hexchat_event_attrs_free (hexchat_plugin *ph, hexchat_event_attrs *attrs) } /* got a server PRIVMSG, NOTICE, numeric etc... */ -int -plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[]) -{ - return plugin_hook_run (sess, name, word, word_eol, NULL, HOOK_SERVER); -} int -plugin_emit_server_attrs (session *sess, char *name, char *word[], char *word_eol[], - time_t server_time) +plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[], + time_t server_time) { hexchat_event_attrs attrs; attrs.server_time_utc = server_time; - return plugin_hook_run (sess, name, word, word_eol, &attrs, HOOK_SERVER_ATTRS); + return plugin_hook_run (sess, name, word, word_eol, &attrs, + HOOK_SERVER | HOOK_SERVER_ATTRS); } /* see if any plugins are interested in this print event */ int -plugin_emit_print (session *sess, char *word[]) -{ - return plugin_hook_run (sess, word[0], word, NULL, NULL, HOOK_PRINT); -} - -int -plugin_emit_print_attrs (session *sess, char *word[], time_t server_time) +plugin_emit_print (session *sess, char *word[], time_t server_time) { hexchat_event_attrs attrs; attrs.server_time_utc = server_time; - return plugin_hook_run (sess, word[0], word, NULL, &attrs, HOOK_PRINT_ATTRS); + return plugin_hook_run (sess, word[0], word, NULL, &attrs, + HOOK_PRINT | HOOK_PRINT_ATTRS); } int @@ -783,12 +777,27 @@ plugin_insert_hook (hexchat_hook *new_hook) { GSList *list; hexchat_hook *hook; + int new_hook_type; + + switch (new_hook->type) + { + case HOOK_PRINT: + case HOOK_PRINT_ATTRS: + new_hook_type = HOOK_PRINT | HOOK_PRINT_ATTRS; + break; + case HOOK_SERVER: + case HOOK_SERVER_ATTRS: + new_hook_type = HOOK_SERVER | HOOK_PRINT_ATTRS; + break; + default: + new_hook_type = new_hook->type; + } list = hook_list; while (list) { hook = list->data; - if (hook && hook->type == new_hook->type && hook->pri <= new_hook->pri) + if (hook && (hook->type & new_hook_type) && hook->pri <= new_hook->pri) { hook_list = g_slist_insert_before (hook_list, list, new_hook); return; @@ -1548,7 +1557,8 @@ hexchat_list_int (hexchat_plugin *ph, hexchat_list *xlist, const char *name) { guint32 hash = str_hash (name); gpointer data = ph->context; - int tmp, type = LIST_CHANNELS; + int tmp = 0; + int type = LIST_CHANNELS; /* a NULL xlist is a shortcut to current "channels" context */ if (xlist) diff --git a/src/common/plugin.h b/src/common/plugin.h index ee9da8c1..cd3f70a8 100644 --- a/src/common/plugin.h +++ b/src/common/plugin.h @@ -170,11 +170,9 @@ int plugin_kill (char *name, int by_filename); void plugin_kill_all (void); void plugin_auto_load (session *sess); int plugin_emit_command (session *sess, char *name, char *word[], char *word_eol[]); -int plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[]); -int plugin_emit_server_attrs (session *sess, char *name, char *word[], - char *word_eol[], time_t server_time); -int plugin_emit_print (session *sess, char *word[]); -int plugin_emit_print_attrs (session *sess, char *word[], time_t server_time); +int plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[], + time_t server_time); +int plugin_emit_print (session *sess, char *word[], time_t server_time); int plugin_emit_dummy_print (session *sess, char *name); int plugin_emit_keypress (session *sess, unsigned int state, unsigned int keyval, int len, char *string); GList* plugin_command_list(GList *tmp_list); diff --git a/src/common/proto-irc.c b/src/common/proto-irc.c index eb60a2e6..6d7c7fc1 100644 --- a/src/common/proto-irc.c +++ b/src/common/proto-irc.c @@ -1503,9 +1503,6 @@ irc_inline (server *serv, char *buf, int len) if (buf[0] == ':') { - int eat1; - int eat2; - /* find a context for this message */ if (is_channel (serv, word[3])) { @@ -1520,11 +1517,8 @@ irc_inline (server *serv, char *buf, int len) word[0] = type; word_eol[1] = buf; /* keep the ":" for plugins */ - eat1 = plugin_emit_server (sess, type, word, word_eol); - eat2 = plugin_emit_server_attrs (sess, type, word, word_eol, - tags_data.timestamp); - - if (eat1 || eat2) + if (plugin_emit_server (sess, type, word, word_eol, + tags_data.timestamp)) goto xit; word[1]++; @@ -1532,16 +1526,10 @@ irc_inline (server *serv, char *buf, int len) } else { - int eat1; - int eat2; - word[0] = type = word[1]; - eat1 = plugin_emit_server (sess, type, word, word_eol); - eat2 = plugin_emit_server_attrs (sess, type, word, word_eol, - tags_data.timestamp); - - if (eat1 || eat2) + if (plugin_emit_server (sess, type, word, word_eol, + tags_data.timestamp)) goto xit; } diff --git a/src/common/servlist.c b/src/common/servlist.c index c85f893a..46f99c5d 100644 --- a/src/common/servlist.c +++ b/src/common/servlist.c @@ -264,6 +264,12 @@ static const struct defaultserver def[] = {0, "irc.indirectirc.com/+6697"}, #endif {0, "irc.indirectirc.com"}, + + {"Interlinked", 0, 0, 0, LOGIN_SASL}, +#ifdef USE_OPENSSL + {0, "irc.interlinked.me/+6697"}, +#endif + {0, "irc.interlinked.me"}, {"IRCHighWay", 0}, #ifdef USE_OPENSSL @@ -457,6 +463,12 @@ static const struct defaultserver def[] = #endif {0, "irc.swiftirc.net/6667"}, + {"Techman's World IRC", 0}, +#ifdef USE_OPENSSL + {0, "irc.techmansworld.com/+6697"}, +#endif + {0, "irc.techmansworld.com/6667"}, + {"TinyCrab", 0, 0, 0, LOGIN_SASL}, {0, "irc.tinycrab.net"}, diff --git a/src/common/text.c b/src/common/text.c index 0b66c5fd..1afb0c18 100644 --- a/src/common/text.c +++ b/src/common/text.c @@ -542,7 +542,7 @@ log_create_pathname (char *servname, char *channame, char *netname) /* insert time/date */ now = time (NULL); tm = localtime (&now); - strftime (fnametime, sizeof (fnametime), fname, tm); + strftime_validated (fnametime, sizeof (fnametime), fname, tm); /* create final path/filename */ if (logmask_is_fullpath ()) @@ -649,14 +649,7 @@ get_stamp_str (char *fmt, time_t tim, char **ret) fmt = loc; } - len = strftime (dest, sizeof (dest), fmt, localtime (&tim)); -#ifdef WIN32 - if (!len) - { - /* use failsafe format until a correct one is specified */ - len = strftime (dest, sizeof (dest), "[%H:%M:%S]", localtime (&tim)); - } -#endif + len = strftime_validated (dest, sizeof (dest), fmt, localtime (&tim)); if (len) { if (prefs.utf8_locale) @@ -2081,8 +2074,6 @@ text_emit (int index, session *sess, char *a, char *b, char *c, char *d, int i; unsigned int stripcolor_args = (chanopt_is_set (prefs.hex_text_stripcolor_msg, sess->text_strip) ? 0xFFFFFFFF : 0); char tbuf[NICKLEN + 4]; - int eat1; - int eat2; if (prefs.hex_text_color_nicks && (index == XP_TE_CHANACTION || index == XP_TE_CHANMSG)) { @@ -2099,10 +2090,7 @@ text_emit (int index, session *sess, char *a, char *b, char *c, char *d, for (i = 5; i < PDIWORDS; i++) word[i] = "\000"; - eat1 = plugin_emit_print (sess, word); - eat2 = plugin_emit_print_attrs (sess, word, timestamp); - - if (eat1 || eat2) + if (plugin_emit_print (sess, word, timestamp)) return; /* If a plugin's callback executes "/close", 'sess' may be invalid */ diff --git a/src/common/userlist.c b/src/common/userlist.c index 4e3a2615..7565fcd4 100644 --- a/src/common/userlist.c +++ b/src/common/userlist.c @@ -150,7 +150,7 @@ userlist_add_hostname (struct session *sess, char *nick, char *hostname, do_rehash = TRUE; user->hostname = strdup (hostname); } - if (!user->realname && realname) + if (!user->realname && realname && *realname) user->realname = strdup (realname); if (!user->servername && servername) user->servername = strdup (servername); @@ -418,7 +418,7 @@ userlist_add (struct session *sess, char *name, char *hostname, { if (account && strcmp (account, "*") != 0) user->account = strdup (account); - if (realname) + if (realname && *realname) user->realname = strdup (realname); } diff --git a/src/common/util.c b/src/common/util.c index cb6181c4..6e912169 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -25,6 +25,7 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <time.h> #include <sys/types.h> #include <sys/stat.h> @@ -2287,3 +2288,80 @@ challengeauth_response (char *username, char *password, char *challenge) return (char *) digest; } #endif + +/** +* \brief Wrapper around strftime for Windows +* +* Prevents crashing when using an invalid format by escaping them. +* +* Behaves the same as strftime with the addition that +* it returns 0 if the escaped format string is too large. +* +* Based upon work from znc-msvc project. +*/ +size_t +strftime_validated (char *dest, size_t destsize, const char *format, const struct tm *time) +{ +#ifndef WIN32 + return strftime (dest, destsize, format, time); +#else + char safe_format[64]; + const char *p = format; + int i = 0; + + if (strlen (format) >= sizeof(safe_format)) + return 0; + + memset (safe_format, 0, sizeof(safe_format)); + + while (*p) + { + if (*p == '%') + { + int has_hash = (*(p + 1) == '#'); + char c = *(p + (has_hash ? 2 : 1)); + + if (i >= sizeof (safe_format)) + return 0; + + switch (c) + { + case 'a': case 'A': case 'b': case 'B': case 'c': case 'd': case 'H': case 'I': case 'j': case 'm': case 'M': + case 'p': case 'S': case 'U': case 'w': case 'W': case 'x': case 'X': case 'y': case 'Y': case 'z': case 'Z': + case '%': + /* formatting code is fine */ + break; + default: + /* replace bad formatting code with itself, escaped, e.g. "%V" --> "%%V" */ + g_strlcat (safe_format, "%%", sizeof(safe_format)); + i += 2; + p++; + break; + } + + /* the current loop run will append % (and maybe #) and the next one will do the actual char. */ + if (has_hash) + { + safe_format[i] = *p; + p++; + i++; + } + if (c == '%') + { + safe_format[i] = *p; + p++; + i++; + } + } + + if (*p) + { + safe_format[i] = *p; + p++; + i++; + } + } + + return strftime (dest, destsize, safe_format, time); +#endif +} diff --git a/src/common/util.h b/src/common/util.h index 6b8d359c..0c54411b 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -83,5 +83,5 @@ char *encode_sasl_pass_plain (char *user, char *pass); char *encode_sasl_pass_blowfish (char *user, char *pass, char *data); char *encode_sasl_pass_aes (char *user, char *pass, char *data); char *challengeauth_response (char *username, char *password, char *challenge); - +size_t strftime_validated (char *dest, size_t destsize, const char *format, const struct tm *time); #endif diff --git a/src/fe-gtk/fe-gtk.vcxproj b/src/fe-gtk/fe-gtk.vcxproj index 7cc40da8..f7341904 100644 --- a/src/fe-gtk/fe-gtk.vcxproj +++ b/src/fe-gtk/fe-gtk.vcxproj @@ -100,8 +100,8 @@ <Command> <![CDATA[ SET SOLUTIONDIR=$(SolutionDir)..\ -"%PROGRAMFILES%\Common Files\microsoft shared\TextTemplating\12.0\TextTransform.exe" -out hexchat.rc hexchat.rc.tt -$(DepsRoot)\bin\glib-compile-resources.exe --generate-source --sourcedir $(DataDir) --target "$(ProjectDir)resources.c" "$(DataDir)hexchat.gresource.xml" +$(TextTransformPath) -out hexchat.rc hexchat.rc.tt +"$(DepsRoot)\bin\glib-compile-resources.exe" --generate-source --sourcedir $(DataDir) --target "$(ProjectDir)resources.c" "$(DataDir)hexchat.gresource.xml" ]]> </Command> <Message>Build hexchat.rc and gresource file</Message> diff --git a/src/fe-gtk/setup.c b/src/fe-gtk/setup.c index b42dbc8a..be5448cb 100644 --- a/src/fe-gtk/setup.c +++ b/src/fe-gtk/setup.c @@ -2114,7 +2114,6 @@ setup_apply (struct hexchatprefs *pr) PangoFontDescription *old_desc; PangoFontDescription *new_desc; char buffer[4 * FONTNAMELEN + 1]; - time_t rawtime; #endif int new_pix = FALSE; int noapply = FALSE; @@ -2192,14 +2191,6 @@ setup_apply (struct hexchatprefs *pr) g_free (old_desc); g_free (new_desc); */ - - /* workaround for strftime differences between POSIX and MSVC */ - time (&rawtime); - - if (!strftime (buffer, sizeof (buffer), prefs.hex_stamp_text_format, localtime (&rawtime)) || !strftime (buffer, sizeof (buffer), prefs.hex_stamp_log_format, localtime (&rawtime))) - { - fe_message (_("Invalid time stamp format! See the strftime MSDN article for details."), FE_MSG_ERROR); - } #endif if (prefs.hex_irc_real_name[0] == 0) diff --git a/src/fe-gtk/xtext.c b/src/fe-gtk/xtext.c index 48d4ec61..f9161b7b 100644 --- a/src/fe-gtk/xtext.c +++ b/src/fe-gtk/xtext.c @@ -139,6 +139,8 @@ static void gtk_xtext_search_textentry_fini (gpointer, gpointer); static void gtk_xtext_search_fini (xtext_buffer *); static gboolean gtk_xtext_search_init (xtext_buffer *buf, const gchar *text, gtk_xtext_search_flags flags, GError **perr); +/* Avoid warning messages for this unused function */ +#if 0 /* gives width of a 8bit string - with no mIRC codes in it */ static int @@ -155,6 +157,7 @@ gtk_xtext_text_width_8bit (GtkXText *xtext, unsigned char *str, int len) return width; } +#endif #define xtext_draw_bg(xt,x,y,w,h) gdk_draw_rectangle(xt->draw_buf, xt->bgc, 1, x, y, w, h); @@ -1319,51 +1322,37 @@ gtk_xtext_timeout_ms (GtkXText *xtext, int pixes) if (apixes < 20) return 20; return 10; } - static gint gtk_xtext_scrolldown_timeout (GtkXText * xtext) { int p_y, win_height; xtext_buffer *buf = xtext->buffer; GtkAdjustment *adj = xtext->adj; - textentry *ent; - - if (buf->last_ent_end == NULL) /* If context has changed */ - { - xtext->scroll_tag = 0; - return 0; - } gdk_window_get_pointer (GTK_WIDGET (xtext)->window, 0, &p_y, 0); gdk_drawable_get_size (GTK_WIDGET (xtext)->window, 0, &win_height); - if (p_y > win_height && - xtext->adj->value < (xtext->adj->upper - xtext->adj->page_size)) - { - xtext->adj->value += buf->pagetop_ent->lines_taken; - ent = buf->last_ent_end->next; - if (ent) - { - gtk_adjustment_value_changed (xtext->adj); - } - else - { - buf->scrollbar_down = TRUE; - } - xtext->scroll_tag = g_timeout_add (gtk_xtext_timeout_ms (xtext, p_y - win_height), - (GSourceFunc) - gtk_xtext_scrolldown_timeout, - xtext); - xtext->select_start_y -= (adj->value - xtext->select_start_adj) * xtext->fontsize; - xtext->select_start_adj = adj->value; - gtk_xtext_selection_draw (xtext, NULL, TRUE); - gtk_xtext_render_ents (xtext, ent, buf->last_ent_end); - } - else + if (buf->last_ent_end == NULL || /* If context has changed OR */ + buf->pagetop_ent == NULL || /* pagetop_ent is reset OR */ + p_y <= win_height || /* pointer not below bottom margin OR */ + adj->value >= adj->upper - adj->page_size) /* we're scrolled to bottom */ { xtext->scroll_tag = 0; + return 0; } + adj->value = (int)adj->value; /* Align to line boundary */ + xtext->select_start_y -= xtext->fontsize; + xtext->select_start_adj++; + adj->value++; + gtk_adjustment_value_changed (adj); + gtk_xtext_selection_draw (xtext, NULL, TRUE); + gtk_xtext_render_ents (xtext, buf->pagetop_ent->next, buf->last_ent_end); + xtext->scroll_tag = g_timeout_add (gtk_xtext_timeout_ms (xtext, p_y - win_height), + (GSourceFunc) + gtk_xtext_scrolldown_timeout, + xtext); + return 0; } @@ -1373,39 +1362,30 @@ gtk_xtext_scrollup_timeout (GtkXText * xtext) int p_y; xtext_buffer *buf = xtext->buffer; GtkAdjustment *adj = xtext->adj; - textentry *ent; - - if (buf->last_ent_start == NULL) /* If context has changed */ - { - xtext->scroll_tag = 0; - return 0; - } gdk_window_get_pointer (GTK_WIDGET (xtext)->window, 0, &p_y, 0); - if (p_y < 0 && adj->value >= 0) - { - buf->scrollbar_down = FALSE; - ent = buf->last_ent_start->prev; - if (ent) - { - adj->value -= ent->lines_taken; - gtk_adjustment_value_changed (adj); - } - xtext->select_start_y -= (adj->value - xtext->select_start_adj) * xtext->fontsize; - xtext->select_start_adj = adj->value; - gtk_xtext_selection_draw (xtext, NULL, TRUE); - gtk_xtext_render_ents (xtext, ent, buf->last_ent_end); - xtext->scroll_tag = g_timeout_add (gtk_xtext_timeout_ms (xtext, p_y), - (GSourceFunc) - gtk_xtext_scrollup_timeout, - xtext); - } - else + if (buf->last_ent_start == NULL || /* If context has changed OR */ + buf->pagetop_ent == NULL || /* pagetop_ent is reset OR */ + p_y >= 0 || /* not above top margin OR */ + adj->value == 0) /* we're scrolled to the top */ { xtext->scroll_tag = 0; + return 0; } + adj->value = (int)adj->value; /* Align to line boundary */ + xtext->select_start_y += xtext->fontsize; + xtext->select_start_adj--; + adj->value--; + gtk_adjustment_value_changed (adj); + gtk_xtext_selection_draw (xtext, NULL, TRUE); + gtk_xtext_render_ents (xtext, buf->pagetop_ent->prev, buf->last_ent_end); + xtext->scroll_tag = g_timeout_add (gtk_xtext_timeout_ms (xtext, p_y), + (GSourceFunc) + gtk_xtext_scrollup_timeout, + xtext); + return 0; } diff --git a/src/fe-text/fe-text.c b/src/fe-text/fe-text.c index 6f197916..76f93d8d 100644 --- a/src/fe-text/fe-text.c +++ b/src/fe-text/fe-text.c @@ -121,7 +121,7 @@ fe_new_window (struct session *sess, int focus) static int get_stamp_str (time_t tim, char *dest, int size) { - return strftime (dest, size, prefs.hex_stamp_text_format, localtime (&tim)); + return strftime_validated (dest, size, prefs.hex_stamp_text_format, localtime (&tim)); } static int diff --git a/win32/hexchat.props b/win32/hexchat.props index 57f77648..3acfd913 100644 --- a/win32/hexchat.props +++ b/win32/hexchat.props @@ -94,6 +94,10 @@ copy "$(HexChatBin)hcsysinfo.dll" "$(HexChatRel)\plugins" xcopy /q /s /i "$(HexChatBin)locale" "$(HexChatRel)\share\locale" xcopy /q /s /i "$(DepsRoot)\share\locale" "$(HexChatRel)\share\locale" </HexChatCopy> + <TextTransformPath Condition="'$(Platform)'=='Win32'">"%PROGRAMFILES%\Common Files\microsoft shared\TextTemplating\12.0\TextTransform.exe"</TextTransformPath> + <TextTransformPath Condition="'$(Platform)'=='x64'">"%PROGRAMFILES(x86)%\Common Files\microsoft shared\TextTemplating\12.0\TextTransform.exe"</TextTransformPath> + <IsccPath Condition="'$(Platform)'=='Win32'">"%PROGRAMFILES%\Inno Setup 5\iscc.exe"</IsccPath> + <IsccPath Condition="'$(Platform)'=='x64'">"%PROGRAMFILES(x86)%\Inno Setup 5\iscc.exe"</IsccPath> </PropertyGroup> <ItemDefinitionGroup> diff --git a/win32/installer/hexchat.iss.tt b/win32/installer/hexchat.iss.tt index 1f2e1491..1ba55303 100644 --- a/win32/installer/hexchat.iss.tt +++ b/win32/installer/hexchat.iss.tt @@ -4,6 +4,9 @@ ;#define APPARCH "x64" ;#define PROJECTDIR "C:\...\hexchat\win32\installer\" +;http://mitrich.net23.net/?/inno-download-plugin.html +#include <idp.iss> + [Setup] AppName=HexChat AppVersion={#APPVER} @@ -57,8 +60,9 @@ Name: "custom"; Description: "Custom Installation"; Flags: iscustom Name: "libs"; Description: "HexChat"; Types: normal minimal custom; Flags: fixed Name: "gtktheme"; Description: "GTK+ Theme"; Types: normal custom; Flags: disablenouninstallwarning Name: "xctext"; Description: "HexChat-Text"; Types: custom; Flags: disablenouninstallwarning -Name: "xtm"; Description: "HexChat Theme Manager (Requires .NET 4.0)"; Types: normal custom; Flags: disablenouninstallwarning +Name: "xtm"; Description: "HexChat Theme Manager"; Types: normal custom; Flags: disablenouninstallwarning Name: "translations"; Description: "Translations"; Types: normal custom; Flags: disablenouninstallwarning +Name: "spell"; Description: "Spelling Dictionaries"; Types: custom; Flags: disablenouninstallwarning Name: "plugins"; Description: "Plugins"; Types: custom; Flags: disablenouninstallwarning Name: "plugins\checksum"; Description: "Checksum"; Types: custom; Flags: disablenouninstallwarning Name: "plugins\dns"; Description: "DNS"; Types: custom; Flags: disablenouninstallwarning @@ -76,7 +80,7 @@ Name: "langs\python\python2"; Description: "Python (requires Python 2.7)"; Types Name: "langs\python\python3"; Description: "Python (requires Python 3.3)"; Types: custom; Flags: disablenouninstallwarning exclusive [Tasks] -Name: portable; Description: "Yes"; GroupDescription: "Portable Install (no Registry entries, no Start Menu icons, no uninstaller):"; Flags: unchecked +Name: portable; Description: "Yes"; GroupDescription: "Portable Mode: Stores configuration files within install directory for portable drives."; Flags: unchecked [Registry] Root: HKCR; Subkey: "irc"; ValueType: none; ValueName: ""; ValueData: ""; Flags: deletekey uninsdeletekey; Tasks: not portable @@ -95,12 +99,12 @@ Root: HKCR; Subkey: ".hct\shell\open\command"; ValueType: string; ValueName: ""; [Run] Filename: "{app}\hexchat.exe"; Description: "Run HexChat after closing the Wizard"; Flags: nowait postinstall skipifsilent -Filename: "https://www.microsoft.com/en-us/download/details.aspx?id=39315"; Description: "Download Visual C++ 2013 Redistributable"; Flags: shellexec runasoriginaluser postinstall skipifsilent -Filename: "http://www.microsoft.com/en-us/download/details.aspx?id=17851"; Description: "Download .NET 4.0 for theme manager"; Components: xtm; Flags: shellexec runasoriginaluser postinstall skipifsilent Filename: "http://docs.hexchat.org/en/latest/changelog.html"; Description: "See what's changed"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked -Filename: "http://hexchat.org/downloads.html"; Description: "Download Perl"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\perl and not langs\python -Filename: "http://hexchat.org/downloads.html"; Description: "Download Python"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\python and not langs\perl -Filename: "http://hexchat.org/downloads.html"; Description: "Download Perl and Python"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked; Components: langs\perl and langs\python +Filename: "{tmp}\vcredist.exe"; Parameters: "/install /quiet /norestart"; StatusMsg: "Installing Visual C++ Redist"; Flags: skipifdoesntexist; Tasks: not portable +Filename: "{tmp}\dotnet4.exe"; Parameters: "/q /norestart"; StatusMsg: "Installing .NET"; Components: xtm; Flags: skipifdoesntexist; Tasks: not portable +Filename: "{tmp}\perl.msi"; StatusMsg: "Installing Perl"; Components: langs\perl; Flags: shellexec skipifdoesntexist; Tasks: not portable +Filename: "{tmp}\python.msi"; StatusMsg: "Installing Python"; Components: langs\python; Flags: shellexec skipifdoesntexist; Tasks: not portable +Filename: "{tmp}\spelling-dicts.exe"; Parameters: "/verysilent"; StatusMsg: "Installing Spelling Dictionaries"; Components: spell; Flags: skipifdoesntexist; Tasks: not portable [Files] Source: "portable-mode"; DestDir: "{app}"; Tasks: portable @@ -182,8 +186,126 @@ BeveledLabel= {#APPNAM} procedure InitializeWizard; begin WizardForm.LicenseAcceptedRadio.Checked := True; + + idpDownloadAfter(wpReady); +end; + +///////////////////////////////////////////////////////////////////// +function GetSysDir(): String; +begin +#if APPARCH != "x64" + if IsWin64 then + Result := ExpandConstant('{syswow64}\') + else + Result := ExpandConstant('{sys}\'); +#else + Result := ExpandConstant('{sys}\'); +#endif +end; + +///////////////////////////////////////////////////////////////////// +function CheckDLL(DLLName: String): Boolean; +var + ResultCode: Integer; +begin + if ExecAsOriginalUser(GetSysDir() + 'where.exe', '/Q ' + DLLName, + '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then + Result := ResultCode = 0 // 0 is success + else + Result := False; +end; + +///////////////////////////////////////////////////////////////////// +function CheckVCInstall(): Boolean; +begin + Result := FileExists(GetSysDir() + 'msvcr120.dll');; +end; + +///////////////////////////////////////////////////////////////////// +function CheckSpellInstall(): Boolean; +begin + Result := DirExists(ExpandConstant('{localappdata}') + '\enchant');; +end; + +///////////////////////////////////////////////////////////////////// +function CheckDotNetInstall(): Boolean; +begin + Result := RegKeyExists(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4'); end; +///////////////////////////////////////////////////////////////////// +// Sets up the automatic downloads +///////////////////////////////////////////////////////////////////// +procedure CurPageChanged(CurPageID: Integer); +var + REDIST: String; + PERL: String; + PY2: String; + PY3: String; + DOTNET: String; + SPELL: String; +begin + if(CurPageID = wpReady) then + begin + idpClearFiles; + + if not IsTaskSelected('portable') then + begin + +#if APPARCH == "x64" + REDIST := 'http://dl.hexchat.net/misc/vcredist_2013_x64.exe'; + PERL := 'http://dl.hexchat.net/misc/perl/Perl%205.18.0%20x64.msi'; + PY2 := 'http://python.org/ftp/python/2.7.5/python-2.7.5.amd64.msi'; + PY3 := 'http://python.org/ftp/python/3.3.2/python-3.3.2.amd64.msi'; +#else + REDIST := 'http://dl.hexchat.net/misc/vcredist_2013_x86.exe'; + PERL := 'http://dl.hexchat.net/misc/perl/Perl%205.18.0%20x86.msi'; + PY2 := 'http://python.org/ftp/python/2.7.5/python-2.7.5.msi'; + PY3 := 'http://python.org/ftp/python/3.3.2/python-3.3.2.msi'; +#endif + DOTNET := 'http://dl.hexchat.net/misc/dotnet_40.exe'; + SPELL := 'http://dl.hexchat.net/hexchat/HexChat%20Spelling%20Dictionaries%20r2.exe'; + + if not CheckVCInstall() then + idpAddFile(REDIST, ExpandConstant('{tmp}\vcredist.exe')); + + if IsComponentSelected('xtm') and not CheckDotNetInstall() then + idpAddFile(DOTNET, ExpandConstant('{tmp}\dotnet4.exe')); + + if IsComponentSelected('spell') and not CheckSpellInstall() then + idpAddFile(SPELL, ExpandConstant('{tmp}\spelling-dicts.exe')); + + if IsComponentSelected('langs\perl') and not CheckDLL('perl518.dll') then + idpAddFile(PERL, ExpandConstant('{tmp}\perl.msi')); + + if IsComponentSelected('langs\python\python2') and not CheckDLL('python27.dll') then + idpAddFile(PY2, ExpandConstant('{tmp}\python.msi')); + + if IsComponentSelected('langs\python\python3') and not CheckDLL('python33.dll') then + idpAddFile(PY3, ExpandConstant('{tmp}\python.msi')); + end; + end; +end; + +///////////////////////////////////////////////////////////////////// +// Disable portable-mode if installing to program files +///////////////////////////////////////////////////////////////////// +function NextButtonClick(CurPageID: Integer): Boolean; +begin + if (CurPageID = wpSelectTasks) then + if (WizardForm.TasksList.Checked[1] = True) then +#if APPARCH == "x64" + if (WizardDirValue() = ExpandConstant('{pf64}\HexChat')) then +#else + if (WizardDirValue() = ExpandConstant('{pf32}\HexChat')) then +#endif + begin + WizardForm.TasksList.Checked[1] := False + MsgBox('Portable mode is only intended for use on portable drives and has been disabled.', mbInformation, MB_OK) + end; + + Result := True; // Always continue +end; ///////////////////////////////////////////////////////////////////// // these are required for x86->x64 or reverse upgrades @@ -211,7 +333,6 @@ begin Result := sUnInstallString; end; - ///////////////////////////////////////////////////////////////////// function IsUpgrade(): Boolean; begin diff --git a/win32/installer/installer.vcxproj b/win32/installer/installer.vcxproj index 453e87bd..09654ab0 100644 --- a/win32/installer/installer.vcxproj +++ b/win32/installer/installer.vcxproj @@ -64,10 +64,10 @@ <Command> <![CDATA[ SET SOLUTIONDIR=$(SolutionDir)..\ -"%PROGRAMFILES%\Common Files\microsoft shared\TextTemplating\12.0\TextTransform.exe" -out "%SOLUTIONDIR%win32\installer\hexchat.iss" "%SOLUTIONDIR%win32\installer\hexchat.iss.tt" +$(TextTransformPath) -out "%SOLUTIONDIR%win32\installer\hexchat.iss" "%SOLUTIONDIR%win32\installer\hexchat.iss.tt" del "$(OutDir)hexchat.iss" type hexchat.iss >> "$(OutDir)hexchat.iss" -"$(ProgramFiles)\Inno Setup 5\iscc.exe" /dPROJECTDIR="$(ProjectDir)" /dAPPARCH="$(Platform)" "$(OutDir)hexchat.iss" +$(IsccPath) /dPROJECTDIR="$(ProjectDir)" /dAPPARCH="$(Platform)" "$(OutDir)hexchat.iss" ]]> </Command> </PreBuildEvent> |