Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ bitlbee.h	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -93,6 +93,4 @@
 #undef g_source_remove
 #define g_source_remove         __PLEASE_USE_B_EVENT_REMOVE__
-#undef g_source_remove_by_user_data
-#define g_source_remove_by_user_data    __PLEASE_USE_B_SOURCE_REMOVE_BY_USER_DATA__
 #undef g_main_run
 #define g_main_run              __PLEASE_USE_B_MAIN_RUN__
Index: configure
===================================================================
--- configure	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ configure	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -56,6 +56,4 @@
 GLIB_MIN_VERSION=2.16
 
-echo BitlBee configure
-
 # Cygwin and Darwin don't support PIC/PIE
 case "$arch" in
@@ -65,4 +63,37 @@
 		pie=0;;
 esac
+
+get_version() {
+	REAL_BITLBEE_VERSION=$(grep '^#define BITLBEE_VERSION ' $srcdir/bitlbee.h | sed 's/.*\"\(.*\)\".*/\1/')
+
+	if [ -n "$BITLBEE_VERSION" ]; then
+		# environment variable already set to something to spoof it
+		# don't replace it with the git stuff
+		return
+	fi
+
+	BITLBEE_VERSION=$REAL_BITLBEE_VERSION
+
+	if [ -d $srcdir/.git ] && type git > /dev/null 2> /dev/null; then
+		timestamp=$(cd $srcdir; git show -s --format=%ci HEAD | sed 's/ .*$//; s/-//g')
+		branch=$(cd $srcdir; git rev-parse --abbrev-ref HEAD)
+
+		search="(.+)-([0-9]+)-(g[0-9a-f]+)"
+		replace="\1+$timestamp+$branch+\2-\3-git"
+
+		BITLBEE_VERSION=$(cd $srcdir; git describe --long --tags | sed -r "s/$search/$replace/")
+
+		unset timestamp branch search replace
+	fi
+}
+
+if [ "$1" = "--dump-version" ]; then
+	srcdir=$(cd $(dirname $0);pwd)
+	get_version
+	echo $BITLBEE_VERSION
+	exit
+fi
+
+echo BitlBee configure
 
 while [ -n "$1" ]; do
@@ -672,32 +703,11 @@
 fi
 
-REAL_BITLBEE_VERSION=`grep '^#define BITLBEE_VERSION ' $srcdir/bitlbee.h | sed 's/.*\"\(.*\)\".*/\1/'`
-echo
-if [ -z "$BITLBEE_VERSION" -a -d .bzr ] && type bzr > /dev/null 2> /dev/null; then
-	nick=`bzr nick`
-	if [ -n "$nick" -a "$nick" != "bitlbee" ]; then
-		nick="-$nick"
-	else
-		nick=""
-	fi
-	rev=`bzr revno`
-	echo 'Using bzr revision #'$rev' as version number'
-	BITLBEE_VERSION=$REAL_BITLBEE_VERSION-bzr$nick-$rev
-fi
-
-if [ -z "$BITLBEE_VERSION" -a -d .git ] && type git > /dev/null 2> /dev/null; then
-	rev=`git describe --long --tags`-`git rev-parse --abbrev-ref HEAD`
-	echo 'Using '$rev' as git version number'
-	BITLBEE_VERSION=$rev-git
-fi
-
-if [ -n "$BITLBEE_VERSION" ]; then
+get_version
+
+if [ "$BITLBEE_VERSION" != "$REAL_BITLBEE_VERSION" ]; then
 	echo 'Spoofing version number: '$BITLBEE_VERSION
 	echo '#undef BITLBEE_VERSION' >> config.h
 	echo '#define BITLBEE_VERSION "'$BITLBEE_VERSION'"' >> config.h
 	echo
-else
-	# for pkg-config
-	BITLBEE_VERSION=$REAL_BITLBEE_VERSION
 fi
 
Index: debian/control
===================================================================
--- debian/control	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ debian/control	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -22,4 +22,5 @@
 Architecture: any
 Depends: ${misc:Depends}, ${shlibs:Depends}, debianutils (>= 1.16), bitlbee-common (= ${source:Version})
+Provides: bitlbee
 Conflicts: bitlbee
 Replaces: bitlbee
Index: doc/user-guide/commands.xml
===================================================================
--- doc/user-guide/commands.xml	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ doc/user-guide/commands.xml	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -121,5 +121,5 @@
 			<description>
 				<para>
-					This commands deletes an account from your account list. You should signoff the account before deleting it.
+					This command deletes an account from your account list. You should signoff the account before deleting it.
 				</para>
 
@@ -853,4 +853,5 @@
 				<varlistentry><term>favourite &lt;screenname|#id&gt;</term><listitem><para>Favo<emphasis>u</emphasis>rite the given user's most recent tweet, or the given tweet ID.</para></listitem></varlistentry>
 				<varlistentry><term>post &lt;message&gt;</term><listitem><para>Post a tweet</para></listitem></varlistentry>
+				<varlistentry><term>url &lt;screenname|#id&gt;</term><listitem><para>Show URL for a tweet to open it in a browser (and see context)</para></listitem></varlistentry>
 			</variablelist>
 
Index: irc_im.c
===================================================================
--- irc_im.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ irc_im.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -50,5 +50,5 @@
 
 	memset(nick, 0, MAX_NICK_LENGTH + 1);
-	strcpy(nick, nick_get(bu));
+	strncpy(nick, nick_get(bu), MAX_NICK_LENGTH);
 
 	bu->ui_data = iu = irc_user_new(irc, nick);
@@ -752,4 +752,6 @@
 			g_free(channel);
 			channel = s;
+		} else {
+			g_free(s);
 		}
 	}
Index: irc_send.c
===================================================================
--- irc_send.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ irc_send.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -175,9 +175,8 @@
 
 	if (iu == irc->user) {
-		irc_write(irc, ":%s MODE %s +%s", irc->root->host, ic->name, ic->mode);
-		irc_send_names(ic);
 		if (ic->topic && *ic->topic) {
 			irc_send_topic(ic, FALSE);
 		}
+		irc_send_names(ic);
 	}
 }
Index: lib/events_glib.c
===================================================================
--- lib/events_glib.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ lib/events_glib.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -82,5 +82,5 @@
 	}
 
-	event_debug("gaim_io_invoke( %d, %d, 0x%x )\n", g_io_channel_unix_get_fd(source), condition, data);
+	event_debug("gaim_io_invoke( %d, %d, %p )\n", g_io_channel_unix_get_fd(source), condition, data);
 
 	st = closure->function(closure->data, g_io_channel_unix_get_fd(source), gaim_cond);
@@ -101,5 +101,5 @@
 static void gaim_io_destroy(gpointer data)
 {
-	event_debug("gaim_io_destroy( 0x%x )\n", data);
+	event_debug("gaim_io_destroy( 0%p )\n", data);
 	g_free(data);
 }
@@ -127,5 +127,5 @@
 	                         gaim_io_invoke, closure, gaim_io_destroy);
 
-	event_debug("b_input_add( %d, %d, 0x%x, 0x%x ) = %d (%p)\n", source, condition, function, data, st, closure);
+	event_debug("b_input_add( %d, %d, %p, %p ) = %d (%p)\n", source, condition, function, data, st, closure);
 
 	g_io_channel_unref(channel);
@@ -140,5 +140,5 @@
 	gint st = g_timeout_add(timeout, (GSourceFunc) func, data);
 
-	event_debug("b_timeout_add( %d, %d, %d ) = %d\n", timeout, func, data, st);
+	event_debug("b_timeout_add( %d, %p, %p ) = %d\n", timeout, func, data, st);
 
 	return st;
Index: lib/oauth.c
===================================================================
--- lib/oauth.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ lib/oauth.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -96,5 +96,5 @@
 {
 	int key_len = strlen(key);
-	GSList *l;
+	GSList *l, *n;
 
 	if (!params) {
@@ -102,5 +102,6 @@
 	}
 
-	for (l = *params; l; l = l->next) {
+	for (l = *params; l; l = n) {
+		n = l->next;
 		char *data = l->data;
 
Index: lib/oauth2.c
===================================================================
--- lib/oauth2.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ lib/oauth2.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -140,7 +140,13 @@
 	struct oauth2_access_token_data *cb_data = req->data;
 	char *atoken = NULL, *rtoken = NULL, *error = NULL;
-	char *content_type;
+	char *content_type = NULL;
 
-	if (getenv("BITLBEE_DEBUG") && req->reply_body) {
+	if (req->status_code <= 0 && !req->reply_body) {
+		cb_data->func(cb_data->data, NULL, NULL, req->status_string);
+		g_free(cb_data);
+		return;
+	}
+
+	if (getenv("BITLBEE_DEBUG")) {
 		printf("%s\n", req->reply_body);
 	}
Index: protocols/jabber/hipchat.c
===================================================================
--- protocols/jabber/hipchat.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ protocols/jabber/hipchat.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -47,14 +47,8 @@
 	jd->flags &= ~JFLAG_STREAM_RESTART;
 
-	if (!jabber_get_roster(ic)) {
-		return XT_ABORT;
-	}
-	if (!jabber_iq_disco_server(ic)) {
-		return XT_ABORT;
-	}
-	if (!jabber_get_hipchat_profile(ic)) {
-		return XT_ABORT;
-	}
-	if (!jabber_iq_disco_muc(ic, muc_host)) {
+	if (!jabber_get_roster(ic) ||
+	    !jabber_iq_disco_server(ic) ||
+	    !jabber_get_hipchat_profile(ic) ||
+            !jabber_iq_disco_muc(ic, muc_host)) {
 		return XT_ABORT;
 	}
@@ -84,6 +78,4 @@
 {
 	struct xt_node *query, *name_node;
-
-	//char *name;
 
 	if (!(query = xt_find_node(node->children, "query"))) {
Index: protocols/jabber/iq.c
===================================================================
--- protocols/jabber/iq.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ protocols/jabber/iq.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -373,4 +373,5 @@
 static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
 {
+	struct jabber_data *jd = ic->proto_data;
 	struct xt_node *query, *c;
 	int initial = (orig != NULL);
@@ -388,5 +389,4 @@
 		char *sub = xt_find_attr(c, "subscription");
 		char *mention_name = xt_find_attr(c, "mention_name");
-		char *nick = mention_name ? : name;
 
 		if (jid && sub) {
@@ -399,6 +399,8 @@
 				}
 
-				if (nick) {
-					imcb_buddy_nick_hint(ic, jid, nick);
+				/* This could also be used to set the full name as nick for fb/gtalk,
+				 * but i'm keeping the old (ugly?) default behavior just to be safe */
+				if (mention_name && (jd->flags & JFLAG_HIPCHAT)) {
+					imcb_buddy_nick_hint(ic, jid, mention_name);
 				}
 			} else if (strcmp(sub, "remove") == 0) {
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ protocols/jabber/jabber.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -428,5 +428,5 @@
 	}
 
-	jabber_get_vcard(ic, bud ? bud->full_jid : who);
+	jabber_get_vcard(ic, who);
 }
 
Index: protocols/msn/gw.c
===================================================================
--- protocols/msn/gw.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ protocols/msn/gw.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -87,12 +87,12 @@
 	gw->polling = FALSE;
 
+	if (req->status_code != 200 || !req->reply_body) {
+		gw->callback(gw->md, -1, B_EV_IO_READ);
+		return;
+	}
+
 	if (getenv("BITLBEE_DEBUG")) {
 		fprintf(stderr, "\n\x1b[90mHTTP:%s\n", req->reply_body);
 		fprintf(stderr, "\n\x1b[97m\n");
-	}
-
-	if (req->status_code != 200) {
-		gw->callback(gw->md, -1, B_EV_IO_READ);
-		return;
 	}
 
@@ -113,5 +113,8 @@
 	if (req->body_size) {
 		g_byte_array_append(gw->in, (const guint8 *) req->reply_body, req->body_size);
-		gw->callback(gw->md, -1, B_EV_IO_READ);
+
+		if (!gw->callback(gw->md, -1, B_EV_IO_READ)) {
+			return;
+		}
 	}
 
Index: protocols/msn/ns.c
===================================================================
--- protocols/msn/ns.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ protocols/msn/ns.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -181,4 +181,5 @@
 		imcb_error(ic, "Error while reading from server");
 		imc_logout(ic, TRUE);
+		g_free(bytes);
 		return FALSE;
 	}
@@ -188,9 +189,5 @@
 	g_free(bytes);
 
-	/* Ignore ret == 0, it's already disconnected then. */
-	msn_handler(md);
-
-	return TRUE;
-	
+	return msn_handler(md);
 }
 
Index: protocols/oscar/ssi.c
===================================================================
--- protocols/oscar/ssi.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ protocols/oscar/ssi.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -66,5 +66,5 @@
 				newitem->gid += 0x0001;
 				for (cur = *list, i = 0; ((cur) && (!i)); cur = cur->next) {
-					if ((cur->gid == newitem->gid) && (cur->gid == newitem->gid)) {
+					if ((cur->bid == newitem->bid) && (cur->gid == newitem->gid)) {
 						i = 1;
 					}
Index: protocols/twitter/twitter.c
===================================================================
--- protocols/twitter/twitter.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ protocols/twitter/twitter.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -483,8 +483,6 @@
 }
 
-static gboolean twitter_length_check(struct im_connection *ic, gchar * msg)
-{
-	int max = set_getint(&ic->acc->set, "message_length"), len;
-	int target_len = set_getint(&ic->acc->set, "target_url_length");
+int twitter_message_len(gchar *msg, int target_len)
+{
 	int url_len_diff = 0;
 
@@ -493,5 +491,14 @@
 	}
 
-	if (max == 0 || (len = g_utf8_strlen(msg, -1) + url_len_diff) <= max) {
+	return g_utf8_strlen(msg, -1) + url_len_diff;
+}
+
+static gboolean twitter_length_check(struct im_connection *ic, gchar * msg)
+{
+	int max = set_getint(&ic->acc->set, "message_length");
+	int target_len = set_getint(&ic->acc->set, "target_url_length");
+	int len = twitter_message_len(msg, target_len);
+
+	if (max == 0 || len <= max) {
 		return TRUE;
 	}
@@ -867,4 +874,6 @@
 }
 
+bee_user_t twitter_log_local_user;
+
 /** Convert the given bitlbee tweet ID, bitlbee username, or twitter tweet ID
  *  into a twitter tweet ID.
@@ -897,8 +906,4 @@
 			bu = td->log[id].bu;
 			id = td->log[id].id;
-			/* Beware of dangling pointers! */
-			if (!g_slist_find(ic->bee->users, bu)) {
-				bu = NULL;
-			}
 		} else if (twitter_parse_id(arg, 10, &id)) {
 			/* Allow normal tweet IDs as well; not a very useful
@@ -911,4 +916,14 @@
 	}
 	if (bu_) {
+		if (bu == &twitter_log_local_user) {
+			/* HACK alert. There's no bee_user object for the local
+			 * user so just fake one for the few cmds that need it. */
+			twitter_log_local_user.handle = td->user;
+		} else {
+			/* Beware of dangling pointers! */
+			if (!g_slist_find(ic->bee->users, bu)) {
+				bu = NULL;
+			}
+		}
 		*bu_ = bu;
 	}
@@ -1003,4 +1018,17 @@
 		in_reply_to = id;
 		allow_post = TRUE;
+	} else if (g_strcasecmp(cmd[0], "url") == 0) {
+		id = twitter_message_id_from_command_arg(ic, cmd[1], &bu);
+		if (!id) {
+			twitter_log(ic, "Tweet `%s' does not exist", cmd[1]);
+		} else {
+			/* More common link is twitter.com/$UID/status/$ID (and that's
+			 * what this will 302 to) but can't generate that since for RTs,
+			 * bu here points at the retweeter while id contains the id of
+			 * the original message. */
+			twitter_log(ic, "https://twitter.com/statuses/%lld", id);
+		}
+		goto eof;
+
 	} else if (g_strcasecmp(cmd[0], "post") == 0) {
 		message += 5;
Index: protocols/twitter/twitter.h
===================================================================
--- protocols/twitter/twitter.h	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ protocols/twitter/twitter.h	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -101,5 +101,7 @@
 struct twitter_log_data {
 	guint64 id;
-	struct bee_user *bu; /* DANGER: can be a dead pointer. Check it first. */
+	/* DANGER: bu can be a dead pointer. Check it first.
+	 * twitter_message_id_from_command_arg() will do this. */
+	struct bee_user *bu;
 };
 
@@ -110,4 +112,12 @@
  */
 extern GSList *twitter_connections;
+
+/**
+ * Evil hack: Fake bee_user which will always point at the local user.
+ * Sometimes used as a return value by twitter_message_id_from_command_arg.
+ * NOT thread safe but don't you dare to even think of ever making BitlBee
+ * threaded. :-)
+ */
+extern bee_user_t twitter_log_local_user;
 
 void twitter_login_finish(struct im_connection *ic);
Index: protocols/twitter/twitter_lib.c
===================================================================
--- protocols/twitter/twitter_lib.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ protocols/twitter/twitter_lib.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -460,5 +460,5 @@
 #endif
 
-static char* expand_entities(char* text, const json_value *entities);
+static void expand_entities(char **text, const json_value *node);
 
 /**
@@ -473,5 +473,5 @@
 {
 	struct twitter_xml_status *txs;
-	const json_value *rt = NULL, *entities = NULL;
+	const json_value *rt = NULL;
 
 	if (node->type != json_object) {
@@ -501,6 +501,4 @@
 		} else if (strcmp("in_reply_to_status_id", k) == 0 && v->type == json_integer) {
 			txs->reply_to = v->u.integer;
-		} else if (strcmp("entities", k) == 0 && v->type == json_object) {
-			entities = v;
 		}
 	}
@@ -516,6 +514,6 @@
 			txs_free(rtxs);
 		}
-	} else if (entities) {
-		txs->text = expand_entities(txs->text, entities);
+	} else {
+		expand_entities(&txs->text, node);
 	}
 
@@ -534,5 +532,4 @@
 {
 	struct twitter_xml_status *txs;
-	const json_value *entities = NULL;
 
 	if (node->type != json_object) {
@@ -561,7 +558,5 @@
 	}
 
-	if (entities) {
-		txs->text = expand_entities(txs->text, entities);
-	}
+	expand_entities(&txs->text, node);
 
 	if (txs->text && txs->user && txs->id) {
@@ -573,6 +568,24 @@
 }
 
-static char* expand_entities(char* text, const json_value *entities)
-{
+static void expand_entities(char **text, const json_value *node)
+{
+	json_value *entities, *quoted;
+	char *quote_url = NULL, *quote_text = NULL;
+
+	if (!((entities = json_o_get(node, "entities")) && entities->type == json_object))
+		return;
+	if ((quoted = json_o_get(node, "quoted_status")) && quoted->type == json_object) {
+		/* New "retweets with comments" feature. Note that this info
+		 * seems to be included in the streaming API only! Grab the
+		 * full message and try to insert it when we run into the
+		 * Tweet entity. */
+		struct twitter_xml_status *txs = twitter_xt_get_status(quoted);
+		quote_text = g_strdup_printf("@%s: %s", txs->user->screen_name, txs->text);
+		quote_url = g_strdup_printf("%s/status/%" G_GUINT64_FORMAT, txs->user->screen_name, txs->id);
+		txs_free(txs);
+	} else {
+		quoted = NULL;
+	}
+
 	JSON_O_FOREACH(entities, k, v) {
 		int i;
@@ -586,4 +599,6 @@
 
 		for (i = 0; i < v->u.array.length; i++) {
+			const char *format = "%s%s <%s>%s";
+
 			if (v->u.array.values[i]->type != json_object) {
 				continue;
@@ -592,20 +607,25 @@
 			const char *kort = json_o_str(v->u.array.values[i], "url");
 			const char *disp = json_o_str(v->u.array.values[i], "display_url");
+			const char *full = json_o_str(v->u.array.values[i], "expanded_url");
 			char *pos, *new;
 
-			if (!kort || !disp || !(pos = strstr(text, kort))) {
+			if (!kort || !disp || !(pos = strstr(*text, kort))) {
 				continue;
 			}
+			if (quote_url && strstr(full, quote_url)) {
+				format = "%s<%s> [%s]%s";
+				disp = quote_text;
+			}
 
 			*pos = '\0';
-			new = g_strdup_printf("%s%s <%s>%s", text, kort,
+			new = g_strdup_printf(format, *text, kort,
 			                      disp, pos + strlen(kort));
 
-			g_free(text);
-			text = new;
-		}
-	}
-
-	return text;
+			g_free(*text);
+			*text = new;
+		}
+	}
+	g_free(quote_text);
+	g_free(quote_url);
 }
 
@@ -681,4 +701,6 @@
 	if (g_strcasecmp(txs->user->screen_name, td->user) == 0) {
 		td->log[td->log_id].id = txs->rt_id;
+		/* More useful than NULL. */
+		td->log[td->log_id].bu = &twitter_log_local_user;
 	}
 
Index: protocols/yahoo/yahoo2.h
===================================================================
--- protocols/yahoo/yahoo2.h	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ protocols/yahoo/yahoo2.h	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -33,6 +33,4 @@
 #undef malloc
 #define malloc(x)             g_malloc(x)
-#undef calloc
-#define calloc(x, y)          g_calloc(x, y)
 #undef realloc
 #define realloc(x, y)         g_realloc(x, y)
Index: unix.c
===================================================================
--- unix.c	(revision 356e2dd647fb26974b799c661763b7a08ccf71de)
+++ unix.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -212,13 +212,23 @@
 		       argv[0], argv[0], argv[0], argv[0], argv[0]);
 	} else if (strcmp(argv[2], "enc") == 0) {
-		pass_len = arc_encode(argv[4], strlen(argv[4]), (unsigned char **) &pass_cr, argv[3], 12);
-		printf("%s\n", base64_encode(pass_cr, pass_len));
+		char *encoded;
+
+		pass_len = arc_encode(argv[4], strlen(argv[4]), &pass_cr, argv[3], 12);
+
+		encoded = base64_encode(pass_cr, pass_len);
+		printf("%s\n", encoded);
+		g_free(encoded);
+		g_free(pass_cr);
 	} else if (strcmp(argv[2], "dec") == 0) {
-		pass_len = base64_decode(argv[4], (unsigned char **) &pass_cr);
+		pass_len = base64_decode(argv[4], &pass_cr);
 		arc_decode(pass_cr, pass_len, (char **) &pass_cl, argv[3]);
 		printf("%s\n", pass_cl);
+
+		g_free(pass_cr);
+		g_free(pass_cl);
 	} else if (strcmp(argv[2], "hash") == 0) {
 		md5_byte_t pass_md5[21];
 		md5_state_t md5_state;
+		char *encoded;
 
 		random_bytes(pass_md5 + 16, 5);
@@ -228,5 +238,7 @@
 		md5_finish(&md5_state, pass_md5);
 
-		printf("%s\n", base64_encode(pass_md5, 21));
+		encoded = base64_encode(pass_md5, 21);
+		printf("%s\n", encoded);
+		g_free(encoded);
 	} else if (strcmp(argv[2], "unhash") == 0) {
 		printf("Hash %s submitted to a massive Beowulf cluster of\n"
