about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJames Booth <boothj5@gmail.com>2012-10-24 20:37:08 +0100
committerJames Booth <boothj5@gmail.com>2012-10-24 20:37:08 +0100
commita8cc6f7c08f34e3fb8c2a84852ad01acea57fa74 (patch)
tree03677f79d7029f347fa2ee35f6e2448a6cbeb0f0
parenta5e4e52567f32356c3ba637bc220ddb6a33248a3 (diff)
parentd6f87e7a1605f5d2086f2fcaa084b258f620f435 (diff)
downloadprofani-tty-a8cc6f7c08f34e3fb8c2a84852ad01acea57fa74.tar.gz
Merge branch 'master' into type_out
Conflicts:
	Makefile.am
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac26
-rwxr-xr-xinstall-all.sh6
-rw-r--r--src/command.c93
-rw-r--r--src/input_win.c13
-rw-r--r--src/preferences.c13
-rw-r--r--src/preferences.h2
-rw-r--r--src/release.c79
-rw-r--r--src/release.h25
-rw-r--r--src/tinyurl.c8
-rw-r--r--src/ui.h6
-rw-r--r--src/windows.c164
12 files changed, 388 insertions, 49 deletions
diff --git a/Makefile.am b/Makefile.am
index ff446943..a7337174 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,7 +7,7 @@ profanity_SOURCES = src/command.c src/contact.c src/history.c src/jabber.h \
 	src/prof_history.c src/ui.h src/common.h src/ contact_list.h src/jabber.c \
 	src/main.c src/profanity.h src/prof_history.h src/chat_log.c \
 	src/chat_log.h src/tinyurl.c src/tinyurl.h src/chat_session.c \
-	src/chat_session.h
+	src/chat_session.h src/release.c src/release.h
 
 TESTS = tests/testsuite
 check_PROGRAMS = tests/testsuite
diff --git a/configure.ac b/configure.ac
index 921885cf..41d59087 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,8 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.65])
-AC_INIT([profanity], [0.1.9dev], [boothj5web@gmail.com])
+AC_INIT([profanity], [0.1.9], [boothj5web@gmail.com])
+AC_DEFINE([PACKAGE_STATUS], ["development"], [Status of this build])
 AC_CONFIG_SRCDIR([src/main.c])
 AC_CONFIG_HEADERS([src/config.h])
 AC_CONFIG_AUX_DIR([build-aux])
@@ -11,19 +12,27 @@ AM_INIT_AUTOMAKE([foreign subdir-objects])
 # Checks for programs.
 AC_PROG_CC
 
+# Options
+AC_ARG_WITH([libxml2],
+    [AS_HELP_STRING([--with-libxml2], [link with libxml2 instead of expat])])
+
 # Checks for libraries.
-AC_CHECK_LIB([ncurses], [main], [], 
-    [AC_MSG_ERROR([ncurses is required for profanity])])
+if test "x$with_libxml2" = xyes; then
+    AC_CHECK_LIB([xml2], [main], [], 
+        [AC_MSG_ERROR([libxml2 is required for profanity])])
+else
+    AC_CHECK_LIB([expat], [main], [], 
+        [AC_MSG_ERROR([expat is required for profanity])])
+fi
+
 AC_CHECK_LIB([resolv], [main], [], 
     [AC_MSG_ERROR([libresolv is required for profanity])])
 AC_CHECK_LIB([ssl], [main], [], 
     [AC_MSG_ERROR([openssl is required for profanity])])
-AC_CHECK_LIB([expat], [main], [], 
-    [AC_MSG_ERROR([expat is required for profanity])])
-AC_CHECK_LIB([xml2], [main], [], 
-    [AC_MSG_ERROR([libxml2 is required for profanity])])
 AC_CHECK_LIB([strophe], [main], [], 
     [AC_MSG_ERROR([libstrophe is required for profanity])])
+AC_CHECK_LIB([ncurses], [main], [], 
+    [AC_MSG_ERROR([ncurses is required for profanity])])
 AC_CHECK_LIB([glib-2.0], [main], [], 
     [AC_MSG_ERROR([glib-2.0 is required for profanity])])
 AC_CHECK_LIB([curl], [main], [], 
@@ -43,8 +52,7 @@ PKG_CHECK_MODULES([NOTIFY], [libnotify], [],
     [AC_MSG_NOTICE([libnotify module not found])])
 
 AM_CFLAGS="-Wall "
-AM_CFLAGS="$AM_CFLAGS -lstrophe -lxml2 -lexpat -lncurses -lcurl -lresolv "
-AM_CFLAGS="$AM_CFLAGS $DEPS_LIBS $NOTIFY_LIBS"
+LIBS="$LIBS $DEPS_LIBS $NOTIFY_LIBS"
 
 AM_CPPFLAGS="$DEPS_CFLAGS $NOTIFY_CFLAGS"
 
diff --git a/install-all.sh b/install-all.sh
index 5bc8fbab..73f2b67d 100755
--- a/install-all.sh
+++ b/install-all.sh
@@ -10,7 +10,7 @@ debian_prepare()
     echo
     echo Profanity installer... installing dependencies
     echo
-    sudo apt-get -y install g++ autoconf libssl-dev libexpat1-dev libncurses5-dev libxml2-dev libglib2.0-dev libnotify-dev libcurl3-dev
+    sudo apt-get -y install g++ autoconf libssl-dev libexpat1-dev libncurses5-dev libglib2.0-dev libnotify-dev libcurl3-dev
 
 }
 
@@ -22,7 +22,7 @@ fedora_prepare()
 
     ARCH=`arch`
     
-    sudo yum -y install gcc gcc-c++ autoconf automake openssl-devel.$ARCH expat-devel.$ARCH ncurses-devel.$ARCH libxml2-devel.$ARCH glib2-devel.$ARCH libnotify-devel.$ARCH libcurl-devel.$ARCH
+    sudo yum -y install gcc gcc-c++ autoconf automake openssl-devel.$ARCH expat-devel.$ARCH ncurses-devel.$ARCH  glib2-devel.$ARCH libnotify-devel.$ARCH libcurl-devel.$ARCH
 }
 
 cygwin_prepare()
@@ -35,7 +35,7 @@ cygwin_prepare()
     chmod +x apt-cyg
     mv apt-cyg /usr/local/bin/
 
-    apt-cyg install make gcc automake autoconf pkg-config openssl-devel expat zlib-devel libncurses-devel libncurses-devel libxml2-devel libglib2.0-devel libcurl-devel libidn-devel libssh2-devel libkrb5-devel openldap-devel
+    apt-cyg install make gcc automake autoconf pkg-config openssl-devel expat zlib-devel libncurses-devel libncurses-devel libglib2.0-devel libcurl-devel libidn-devel libssh2-devel libkrb5-devel openldap-devel
     ln -s /usr/bin/gcc-3.exe /usr/bin/gcc.exe
     ln -s /usr/bin/g++-3.exe /usr/bin/g++.exe
 
diff --git a/src/command.c b/src/command.c
index 79b92ffc..b30e9cae 100644
--- a/src/command.c
+++ b/src/command.c
@@ -61,6 +61,7 @@ static gboolean _cmd_set_boolean_preference(const char * const inp,
 // command prototypes
 static gboolean _cmd_quit(const char * const inp, struct cmd_help_t help);
 static gboolean _cmd_help(const char * const inp, struct cmd_help_t help);
+static gboolean _cmd_about(const char * const inp, struct cmd_help_t help);
 static gboolean _cmd_prefs(const char * const inp, struct cmd_help_t help);
 static gboolean _cmd_who(const char * const inp, struct cmd_help_t help);
 static gboolean _cmd_connect(const char * const inp, struct cmd_help_t help);
@@ -75,6 +76,7 @@ static gboolean _cmd_set_showsplash(const char * const inp, struct cmd_help_t he
 static gboolean _cmd_set_chlog(const char * const inp, struct cmd_help_t help);
 static gboolean _cmd_set_history(const char * const inp, struct cmd_help_t help);
 static gboolean _cmd_set_remind(const char * const inp, struct cmd_help_t help);
+static gboolean _cmd_vercheck(const char * const inp, struct cmd_help_t help);
 static gboolean _cmd_away(const char * const inp, struct cmd_help_t help);
 static gboolean _cmd_online(const char * const inp, struct cmd_help_t help);
 static gboolean _cmd_dnd(const char * const inp, struct cmd_help_t help);
@@ -91,15 +93,25 @@ static struct cmd_t main_commands[] =
 {
     { "/help",
         _cmd_help,
-        { "/help [command]", "Show help summary, or help on a specific command",
-        { "/help [command]",
-          "---------------",
-          "List all commands with short help on what they do.",
+        { "/help [area|command]", "Show help summary, or help on a specific area or command",
+        { "/help [area|command]",
+          "--------------------",
+          "Show help options.",
+          "Specify an area (basic, status, settings, navigation) for more help on that area.",
           "Specify the command if you want more detailed help on a specific command.",
           "",
           "Example : /help connect",
+          "Example : /help settings",
           NULL } } },
 
+    { "/about",
+        _cmd_about,
+        { "/about", "About Profanity",
+        { "/about",
+          "------",
+          "Show versioning and license information.",
+          NULL  } } },
+
     { "/connect",
         _cmd_connect,
         { "/connect user@host", "Login to jabber.",
@@ -260,6 +272,16 @@ static struct cmd_t setting_commands[] =
           "Config file section : [ui]",
           "Config file value :   showsplash=true|false",
           NULL } } },
+    
+    { "/vercheck",
+        _cmd_vercheck,
+        { "/vercheck [on|off]", "Check for a new release.",
+        { "/vercheck [on|off]",
+          "------------------",
+          "Without a parameter will check for a new release.",
+          "Switching on or off will enable/disable a version check when Profanity starts,",
+          "and each time the /about command is run.",
+          NULL  } } },
 
     { "/chlog",
         _cmd_set_chlog,
@@ -363,6 +385,10 @@ cmd_init(void)
     log_info("Initialising commands");
     commands_ac = p_autocomplete_new();
     help_ac = p_autocomplete_new();
+    p_autocomplete_add(help_ac, strdup("basic"));
+    p_autocomplete_add(help_ac, strdup("status"));
+    p_autocomplete_add(help_ac, strdup("settings"));
+    p_autocomplete_add(help_ac, strdup("navigation"));
 
     unsigned int i;
     for (i = 0; i < ARRAY_SIZE(main_commands); i++) {
@@ -551,6 +577,14 @@ _cmd_help(const char * const inp, struct cmd_help_t help)
 {
     if (strcmp(inp, "/help") == 0) {
         cons_help();
+    } else if (strcmp(inp, "/help basic") == 0) {
+        cons_basic_help();
+    } else if (strcmp(inp, "/help status") == 0) {
+        cons_status_help();
+    } else if (strcmp(inp, "/help settings") == 0) {
+        cons_settings_help();
+    } else if (strcmp(inp, "/help navigation") == 0) {
+        cons_navigation_help();
     } else {
         char *cmd = strndup(inp+6, strlen(inp)-6);
         char cmd_with_slash[1 + strlen(cmd) + 1];
@@ -581,6 +615,14 @@ _cmd_help(const char * const inp, struct cmd_help_t help)
 }
 
 static gboolean
+_cmd_about(const char * const inp, struct cmd_help_t help)
+{
+    cons_show("");
+    cons_about();
+    return TRUE;
+}
+
+static gboolean
 _cmd_prefs(const char * const inp, struct cmd_help_t help)
 {
     cons_prefs();
@@ -711,6 +753,10 @@ _cmd_tiny(const char * const inp, struct cmd_help_t help)
 {
     if (strlen(inp) > 6) {
         char *url = strndup(inp+6, strlen(inp)-6);
+        if (url == NULL) {
+            log_error("Not enough memory.");
+            return FALSE;
+        }
 
         if (!tinyurl_valid(url)) {
             GString *error = g_string_new("/tiny, badly formed URL: ");
@@ -720,25 +766,28 @@ _cmd_tiny(const char * const inp, struct cmd_help_t help)
                 win_bad_show(error->str);
             }
             g_string_free(error, TRUE);
-            free(url);
         } else if (win_in_chat()) {
             char *tiny = tinyurl_get(url);
-            char *recipient = win_get_recipient();
-            jabber_send(tiny, recipient);
 
-            if (prefs_get_chlog()) {
-                const char *jid = jabber_get_jid();
-                chat_log_chat(jid, recipient, tiny, OUT);
-            }
+            if (tiny != NULL) {
+                char *recipient = win_get_recipient();
+                jabber_send(tiny, recipient);
 
-            win_show_outgoing_msg("me", recipient, tiny);
-            free(recipient);
-            free(tiny);
-            free(url);
+                if (prefs_get_chlog()) {
+                    const char *jid = jabber_get_jid();
+                    chat_log_chat(jid, recipient, tiny, OUT);
+                }
+
+                win_show_outgoing_msg("me", recipient, tiny);
+                free(recipient);
+                free(tiny);
+            } else {
+                cons_bad_show("Couldn't get tinyurl.");
+            }
         } else {
             cons_bad_command(inp);
-            free(url);
         }
+        free(url);
     } else {
         cons_show("Usage: %s", help.usage);
 
@@ -783,6 +832,18 @@ _cmd_set_typing(const char * const inp, struct cmd_help_t help)
 }
 
 static gboolean
+_cmd_vercheck(const char * const inp, struct cmd_help_t help)
+{
+    if (strcmp(inp, "/vercheck") == 0) {
+        cons_check_version(TRUE);
+        return TRUE;
+    } else {
+        return _cmd_set_boolean_preference(inp, help, "/vercheck",
+            "Version checking", prefs_set_vercheck);
+    }
+}
+
+static gboolean
 _cmd_set_flash(const char * const inp, struct cmd_help_t help)
 {
     return _cmd_set_boolean_preference(inp, help, "/flash",
diff --git a/src/input_win.c b/src/input_win.c
index 107d6985..3cb903e1 100644
--- a/src/input_win.c
+++ b/src/input_win.c
@@ -72,6 +72,12 @@ static void _parameter_autocomplete(char *input, int *size, char *command,
 void
 create_input_window(void)
 {
+#ifdef NCURSES_REENTRANT
+    set_escdelay(25);
+#else
+    ESCDELAY = 25;
+#endif
+
     int rows, cols;
     getmaxyx(stdscr, rows, cols);
 
@@ -220,6 +226,11 @@ _handle_edit(const int ch, char *input, int *size)
 
     switch(ch) {
 
+    case 27: // ESC
+        *size = 0;
+        inp_clear();
+        return 1;
+
     case 127:
     case KEY_BACKSPACE:
         contact_list_reset_search_attempts();
@@ -361,6 +372,8 @@ _handle_edit(const int ch, char *input, int *size)
             prefs_autocomplete_boolean_choice);
         _parameter_autocomplete(input, size, "/history",
             prefs_autocomplete_boolean_choice);
+        _parameter_autocomplete(input, size, "/vercheck",
+            prefs_autocomplete_boolean_choice);
 
         return 1;
 
diff --git a/src/preferences.c b/src/preferences.c
index 67f9345a..706ad4d3 100644
--- a/src/preferences.c
+++ b/src/preferences.c
@@ -262,6 +262,19 @@ prefs_set_typing(gboolean value)
 }
 
 gboolean
+prefs_get_vercheck(void)
+{
+    return g_key_file_get_boolean(prefs, "ui", "vercheck", NULL);
+}
+
+void
+prefs_set_vercheck(gboolean value)
+{
+    g_key_file_set_boolean(prefs, "ui", "vercheck", value);
+    _save_prefs();
+}
+
+gboolean
 prefs_get_flash(void)
 {
     return g_key_file_get_boolean(prefs, "ui", "flash", NULL);
diff --git a/src/preferences.h b/src/preferences.h
index e816b7c0..885b895d 100644
--- a/src/preferences.h
+++ b/src/preferences.h
@@ -58,6 +58,8 @@ gboolean prefs_get_showsplash(void);
 void prefs_set_showsplash(gboolean value);
 gint prefs_get_remind(void);
 void prefs_set_remind(gint value);
+gboolean prefs_get_vercheck(void);
+void prefs_set_vercheck(gboolean value);
 
 void prefs_add_login(const char *jid);
 
diff --git a/src/release.c b/src/release.c
new file mode 100644
index 00000000..f585e8fc
--- /dev/null
+++ b/src/release.c
@@ -0,0 +1,79 @@
+/*
+ * release.c
+ *
+ * Copyright (C) 2012 James Booth <boothj5@gmail.com>
+ *
+ * This file is part of Profanity.
+ *
+ * Profanity is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Profanity is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Profanity.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <curl/curl.h>
+#include <curl/easy.h>
+
+struct curl_data_t
+{
+    char *buffer;
+    size_t size;
+};
+
+static size_t _data_callback(void *ptr, size_t size, size_t nmemb, void *data);
+
+char *
+release_get_latest()
+{
+    char *url = "http://www.boothj5.com/profanity_version.txt";
+
+    CURL *handle = curl_easy_init();
+    struct curl_data_t output;
+    output.buffer = NULL;
+    output.size = 0;
+
+    curl_easy_setopt(handle, CURLOPT_URL, url);
+    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, _data_callback);
+    curl_easy_setopt(handle, CURLOPT_TIMEOUT, 2);
+    curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)&output);
+
+    curl_easy_perform(handle);
+    curl_easy_cleanup(handle);
+
+    if (output.buffer != NULL) {
+        output.buffer[output.size++] = '\0';
+        return output.buffer;
+    } else {
+        return NULL;
+    }
+}
+
+static size_t
+_data_callback(void *ptr, size_t size, size_t nmemb, void *data)
+{
+    size_t realsize = size * nmemb;
+    struct curl_data_t *mem = (struct curl_data_t *) data;
+    mem->buffer = realloc(mem->buffer, mem->size + realsize + 1);
+
+    if ( mem->buffer )
+    {
+        memcpy( &( mem->buffer[ mem->size ] ), ptr, realsize );
+        mem->size += realsize;
+        mem->buffer[ mem->size ] = 0;
+    }
+
+    return realsize;
+}
diff --git a/src/release.h b/src/release.h
new file mode 100644
index 00000000..c106d622
--- /dev/null
+++ b/src/release.h
@@ -0,0 +1,25 @@
+/*
+ * release.h
+ *
+ * Copyright (C) 2012 James Booth <boothj5@gmail.com>
+ *
+ * This file is part of Profanity.
+ *
+ * Profanity is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Profanity is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Profanity.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <glib.h>
+
+char * release_get_latest(void);
diff --git a/src/tinyurl.c b/src/tinyurl.c
index 9b572319..9ee64977 100644
--- a/src/tinyurl.c
+++ b/src/tinyurl.c
@@ -60,10 +60,14 @@ tinyurl_get(char *url)
     curl_easy_perform(handle);
     curl_easy_cleanup(handle);
 
-    output.buffer[output.size++] = '\0';
     g_string_free(full_url, TRUE);
 
-    return output.buffer;
+    if (output.buffer != NULL) {
+        output.buffer[output.size++] = '\0';
+        return output.buffer;
+    } else {
+        return NULL;
+    }
 }
 
 static size_t
diff --git a/src/ui.h b/src/ui.h
index 671ca703..df42a191 100644
--- a/src/ui.h
+++ b/src/ui.h
@@ -103,13 +103,19 @@ void win_bad_show(const char * const msg);
 void win_remind(void);
 
 // console window actions
+void cons_about(void);
 void cons_help(void);
+void cons_basic_help(void);
+void cons_settings_help(void);
+void cons_status_help(void);
+void cons_navigation_help(void);
 void cons_prefs(void);
 void cons_bad_command(const char * const cmd);
 void cons_show(const char * const cmd, ...);
 void cons_bad_show(const char * const cmd);
 void cons_highlight_show(const char * const cmd);
 void cons_show_contacts(GSList * list);
+void cons_check_version(gboolean not_available_msg);
 
 // status bar actions
 void status_bar_refresh(void);
diff --git a/src/windows.c b/src/windows.c
index 8fe78365..bd06165d 100644
--- a/src/windows.c
+++ b/src/windows.c
@@ -42,6 +42,7 @@
 #include "contact_list.h"
 #include "log.h"
 #include "preferences.h"
+#include "release.h"
 #include "ui.h"
 
 #define CONS_WIN_TITLE "_cons"
@@ -86,6 +87,7 @@ static void _win_resize_all(void);
 static gint _win_get_unread(void);
 static void _win_show_history(WINDOW *win, int win_index,
     const char * const contact);
+static gboolean _new_release(char *found_version);
 
 #ifdef HAVE_LIBNOTIFY
 static void _win_notify(const char * const message, int timeout,
@@ -541,6 +543,11 @@ cons_prefs(void)
     else
         cons_show("Chat history            : OFF");
 
+    if (prefs_get_vercheck())
+        cons_show("Version checking        : ON");
+    else
+        cons_show("Version checking        : OFF");
+
     gint remind_period = prefs_get_remind();
     if (remind_period == 0) {
         cons_show("Message reminder period : OFF");
@@ -575,9 +582,33 @@ void
 cons_help(void)
 {
     cons_show("");
+    cons_show("Choose an area you need help with:");
+    cons_show("");
+    cons_show("/help basic      - Basic commands, for connecting, chatting etc.");
+    cons_show("/help status     - How to change your status.");
+    cons_show("/help settings   - Commands for configuring Profanity.");
+    cons_show("/help navigation - How to navigate around Profanity.");
+    cons_show("");
+
+    if (_curr_prof_win == 0)
+        dirty = TRUE;
+}
+
+void
+cons_basic_help(void)
+{
+    cons_show("");
     cons_show("Basic Commands:");
     _cons_show_basic_help();
 
+    if (_curr_prof_win == 0)
+        dirty = TRUE;
+}
+
+void
+cons_settings_help(void)
+{
+    cons_show("");
     cons_show("Settings:");
     cons_show("");
 
@@ -589,6 +620,15 @@ cons_help(void)
     }
 
     cons_show("");
+
+    if (_curr_prof_win == 0)
+        dirty = TRUE;
+}
+
+void
+cons_status_help(void)
+{
+    cons_show("");
     cons_show("Status changes:");
     cons_show("");
 
@@ -600,12 +640,22 @@ cons_help(void)
     }
 
     cons_show("");
+
+    if (_curr_prof_win == 0)
+        dirty = TRUE;
+}
+
+void
+cons_navigation_help(void)
+{
+    cons_show("");
     cons_show("Navigation:");
     cons_show("");
     cons_show("F1                       : This console window.");
     cons_show("F2-F10                   : Chat windows.");
     cons_show("UP, DOWN                 : Navigate input history.");
     cons_show("LEFT, RIGHT, HOME, END   : Edit current input.");
+    cons_show("ESC                      : Clear current input.");
     cons_show("TAB                      : Autocomplete command/recipient/login");
     cons_show("PAGE UP, PAGE DOWN       : Page the main window.");
     cons_show("");
@@ -730,8 +780,7 @@ win_page_off(void)
 static void
 _create_windows(void)
 {
-    int rows, cols;
-    getmaxyx(stdscr, rows, cols);
+    int cols = getmaxx(stdscr);
     max_cols = cols;
 
     // create the console window in 0
@@ -746,13 +795,43 @@ _create_windows(void)
     scrollok(cons.win, TRUE);
 
     _wins[0] = cons;
+
+    cons_about();
+
+    // create the chat windows
+    int i;
+    for (i = 1; i < NUM_WINS; i++) {
+        struct prof_win chat;
+        strcpy(chat.from, "");
+        chat.win = newpad(PAD_SIZE, cols);
+        wbkgd(chat.win, COLOUR_TEXT);
+        chat.y_pos = 0;
+        chat.paged = 0;
+        chat.unread = 0;
+        chat.history_shown = 0;
+        scrollok(chat.win, TRUE);
+        _wins[i] = chat;
+    }
+}
+
+void
+cons_about(void)
+{
+    int rows, cols;
+    getmaxyx(stdscr, rows, cols);
+
     _cons_win = _wins[0].win;
 
     if (prefs_get_showsplash()) {
         _cons_splash_logo();
     } else {
         _win_show_time(_cons_win);
-        wprintw(_cons_win, "Welcome to Profanity, version %s\n", PACKAGE_VERSION);
+
+        if (strcmp(PACKAGE_STATUS, "development") == 0) {
+            wprintw(_cons_win, "Welcome to Profanity, version %sdev\n", PACKAGE_VERSION);
+        } else {
+            wprintw(_cons_win, "Welcome to Profanity, version %s\n", PACKAGE_VERSION);
+        }
     }
 
     _win_show_time(_cons_win);
@@ -772,23 +851,69 @@ _create_windows(void)
     _win_show_time(_cons_win);
     wprintw(_cons_win, "\n");
 
+    if (prefs_get_vercheck()) {
+        cons_check_version(FALSE);
+    }
+
     prefresh(_cons_win, 0, 0, 1, 0, rows-3, cols-1);
 
     dirty = TRUE;
+}
 
-    // create the chat windows
-    int i;
-    for (i = 1; i < NUM_WINS; i++) {
-        struct prof_win chat;
-        strcpy(chat.from, "");
-        chat.win = newpad(PAD_SIZE, cols);
-        wbkgd(chat.win, COLOUR_TEXT);
-        chat.y_pos = 0;
-        chat.paged = 0;
-        chat.unread = 0;
-        chat.history_shown = 0;
-        scrollok(chat.win, TRUE);
-        _wins[i] = chat;
+void
+cons_check_version(gboolean not_available_msg)
+{
+    char *latest_release = release_get_latest();
+
+    if (latest_release != NULL) {
+        gboolean relase_valid = g_regex_match_simple("^\\d+\\.\\d+\\.\\d+$", latest_release, 0, 0);
+
+        if (relase_valid) {
+            if (_new_release(latest_release)) {
+                _win_show_time(_cons_win);
+                wattron(_cons_win, COLOUR_ONLINE);
+                wprintw(_cons_win, "A new version of Profanity is available: %s", latest_release);
+                wattroff(_cons_win, COLOUR_ONLINE);
+                _win_show_time(_cons_win);
+                wattron(_cons_win, COLOUR_ONLINE);
+                wprintw(_cons_win, "Check http://www.boothj5.com/profanity.shtml for details.\n");
+                wattroff(_cons_win, COLOUR_ONLINE);
+                free(latest_release);
+                _win_show_time(_cons_win);
+                wprintw(_cons_win, "\n");
+            } else {
+                if (not_available_msg) {
+                    cons_show("No new version available.");
+                    cons_show("");
+                }
+            }
+        }
+    }
+}
+
+static gboolean
+_new_release(char *found_version)
+{
+    int curr_maj, curr_min, curr_patch, found_maj, found_min, found_patch;
+
+    int parse_curr = sscanf(PACKAGE_VERSION, "%d.%d.%d", &curr_maj, &curr_min,
+        &curr_patch);
+    int parse_found = sscanf(found_version, "%d.%d.%d", &found_maj, &found_min,
+        &found_patch);
+
+    if (parse_found == 3 && parse_curr == 3) {
+        if (found_maj > curr_maj) {
+            return TRUE;
+        } else if (found_maj == curr_maj && found_min > curr_min) {
+            return TRUE;
+        } else if (found_maj == curr_maj && found_min == curr_min
+                                        && found_patch > curr_patch) {
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    } else {
+        return FALSE;
     }
 }
 
@@ -798,7 +923,6 @@ _cons_splash_logo(void)
     _win_show_time(_cons_win);
     wprintw(_cons_win, "Welcome to\n");
 
-
     _win_show_time(_cons_win);
     wattron(_cons_win, COLOUR_OFFLINE);
     wprintw(_cons_win, "                   ___            _           \n");
@@ -837,7 +961,11 @@ _cons_splash_logo(void)
     _win_show_time(_cons_win);
     wprintw(_cons_win, "\n");
     _win_show_time(_cons_win);
-    wprintw(_cons_win, "Version %s\n", PACKAGE_VERSION);
+    if (strcmp(PACKAGE_STATUS, "dev") == 0) {
+        wprintw(_cons_win, "Version %sdev\n", PACKAGE_VERSION);
+    } else {
+        wprintw(_cons_win, "Version %s\n", PACKAGE_VERSION);
+    }
 }
 
 static int