diff --git a/src/common/url.c b/src/common/url.c index 6c429ed8..351aeb03 100644 --- a/src/common/url.c +++ b/src/common/url.c @@ -35,6 +35,7 @@ GTree *url_btree = NULL; static int do_an_re (const char *word, int *start, int *end, int *type); static GRegex *re_url (void); static GRegex *re_host (void); +static GRegex *re_host6 (void); static GRegex *re_email (void); static GRegex *re_nick (void); static GRegex *re_channel (void); @@ -222,6 +223,7 @@ url_check_word (const char *word) /* Fall through */ case WORD_URL: case WORD_HOST: + case WORD_HOST6: case WORD_CHANNEL: case WORD_PATH: return lasttype; @@ -306,7 +308,7 @@ url_last (int *lstart, int *lend) } static int -do_an_re(const char *word,int *start, int *end, int *type) +do_an_re(const char *word, int *start, int *end, int *type) { typedef struct func_s { GRegex *(*fn)(void); @@ -314,9 +316,10 @@ do_an_re(const char *word,int *start, int *end, int *type) } func_t; func_t funcs[] = { - { re_email, WORD_EMAIL }, { re_url, WORD_URL }, + { re_email, WORD_EMAIL }, { re_channel, WORD_CHANNEL }, + { re_host6, WORD_HOST6 }, { re_host, WORD_HOST }, { re_path, WORD_PATH }, { re_nick, WORD_NICK } @@ -349,17 +352,23 @@ do_an_re(const char *word,int *start, int *end, int *type) /* Miscellaneous description --- */ #define DOMAIN "[a-z0-9][-a-z0-9]*(\\.[-a-z0-9]+)*\\." #define TLD "[a-z][-a-z0-9]*[a-z]" -#define IPADDR "[0-9]+(\\.[0-9]+){3}" -#define HOST "(" DOMAIN TLD "|" IPADDR ")" -#define OPT_PORT "(:[1-9][0-9]{0,4})?" +#define IPADDR "[0-9]{1,3}(\\.[0-9]{1,3}){3}" +#define IPV6GROUP "([0-9a-f]{0,4})" +#define IPV6ADDR "((" IPV6GROUP "(:" IPV6GROUP "){7})" \ + "|(" IPV6GROUP "(:" IPV6GROUP ")*:(:" IPV6GROUP ")+))" /* with :: compression */ +#define HOST "(" DOMAIN TLD "|" IPADDR "|" IPV6ADDR ")" +/* In urls the IPv6 must be enclosed in square brackets */ +#define HOST_URL "(" DOMAIN TLD "|" IPADDR "|" "\\[" IPV6ADDR "\\]" ")" +#define PORT "(:[1-9][0-9]{0,4})" +#define OPT_PORT "(" PORT ")?" GRegex * -make_re(char *grist, char *type) +make_re (char *grist) { GRegex *ret; GError *err = NULL; - ret = g_regex_new (grist, G_REGEX_CASELESS + G_REGEX_OPTIMIZE, 0, &err); + ret = g_regex_new (grist, G_REGEX_CASELESS | G_REGEX_OPTIMIZE, 0, &err); g_free (grist); return ret; } @@ -375,78 +384,163 @@ re_host (void) if (host_ret) return host_ret; grist = g_strdup_printf ( - "(" /* HOST */ - HOST OPT_PORT + "(" + "(" HOST_URL PORT ")|(" HOST ")" ")" ); - host_ret = make_re (grist, "re_host"); + host_ret = make_re (grist); return host_ret; } +static GRegex * +re_host6 (void) +{ + static GRegex *host6_ret; + char *grist; + + if (host6_ret) return host6_ret; + + grist = g_strdup_printf ( + "(" + "(" IPV6ADDR ")|(" "\\[" IPV6ADDR "\\]" PORT ")" + ")" + ); + + host6_ret = make_re (grist); + + return host6_ret; +} + /* URL description --- */ #define SCHEME "(%s)" #define LPAR "\\(" #define RPAR "\\)" #define NOPARENS "[^() \t]*" +#define PATH \ + "(" \ + "(" LPAR NOPARENS RPAR ")" \ + "|" \ + "(" NOPARENS ")" \ + ")*" /* Zero or more occurrences of either of these */ \ + "(?0 will be displayed as a link by gtk_xtext_motion_notify() */ #define WORD_DIALOG -1 #define WORD_PATH -2 diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c index 28a3b1d5..6890286f 100644 --- a/src/fe-gtk/fe-gtk.c +++ b/src/fe-gtk/fe-gtk.c @@ -1008,11 +1008,13 @@ fe_open_url_inner (const char *url) static void fe_open_url_locale (const char *url) { - if (url_check_word (url) == WORD_PATH) + int url_type = url_check_word (url); + char *uri; + + /* gvfs likes file:// */ + if (url_type == WORD_PATH) { #ifndef WIN32 - char *uri; - uri = g_strconcat ("file://", url, NULL); fe_open_url_inner (uri); g_free (uri); @@ -1020,6 +1022,18 @@ fe_open_url_locale (const char *url) fe_open_url_inner (url); #endif } + /* IPv6 addr. Add http:// */ + else if (url_type == WORD_HOST6) + { + /* IPv6 addrs in urls should be enclosed in [ ] */ + if (*url != '[') + uri = g_strdup_printf ("http://[%s]", url); + else + uri = g_strdup_printf ("http://%s", url); + + fe_open_url_inner (uri); + g_free (uri); + } /* the http:// part's missing, prepend it, otherwise it won't always work */ else if (strchr (url, ':') == NULL) { diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c index 100642e1..2a486b17 100644 --- a/src/fe-gtk/maingui.c +++ b/src/fe-gtk/maingui.c @@ -2267,6 +2267,7 @@ mg_word_clicked (GtkWidget *xtext, char *word, GdkEventButton *even) switch (word_type) { case WORD_URL: + case WORD_HOST6: case WORD_HOST: word[end] = 0; fe_open_url (word + start); @@ -2293,6 +2294,7 @@ mg_word_clicked (GtkWidget *xtext, char *word, GdkEventButton *even) menu_middlemenu (sess, even); break; case WORD_URL: + case WORD_HOST6: case WORD_HOST: word[end] = 0; word += start;