Index: configure
===================================================================
--- configure (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ configure (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -82,5 +82,5 @@
replace="\1+$timestamp+$branch+\2-\3-git"
- BITLBEE_VERSION=$(cd $srcdir; git describe --long --tags | sed -r "s/$search/$replace/")
+ BITLBEE_VERSION=$(cd $srcdir; git describe --long --tags | sed -r "s#$search#$replace#")
unset timestamp branch search replace
Index: debian/control
===================================================================
--- debian/control (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ debian/control (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -22,5 +22,5 @@
Architecture: any
Depends: ${misc:Depends}, ${shlibs:Depends}, debianutils (>= 1.16), bitlbee-common (= ${source:Version})
-Provides: bitlbee
+Provides: bitlbee (= ${source:Version})
Conflicts: bitlbee
Replaces: bitlbee
Index: doc/user-guide/commands.xml
===================================================================
--- doc/user-guide/commands.xml (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ doc/user-guide/commands.xml (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -1017,5 +1017,16 @@
- Some protocols (MSN, Yahoo!) can notify via IM about new e-mail. Since most people use their Hotmail/Yahoo! addresses as a spam-box, this is disabled default. If you want these notifications, you can enable this setting.
+ Some protocols (MSN, Yahoo!, GTalk) can notify via IM about new e-mail. Since most people use their Hotmail/Yahoo! addresses as a spam-box, this is disabled default. If you want these notifications, you can enable this setting.
+
+
+
+
+
+
+ empty
+
+
+
+ This setting is available for protocols with e-mail notification functionality. If set to empty all e-mail notifications will go to control channel, if set to some string - this will be the name of a contact who will PRIVMSG you on every new notification.
Index: irc.h
===================================================================
--- irc.h (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ irc.h (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -147,4 +147,7 @@
IRC_CHANNEL_TEMP = 2, /* Erase the channel when the user leaves,
and don't save it. */
+
+ /* Show a placeholder of the channel in listings, but don't save it */
+ IRC_CHANNEL_KEEP_PLACEHOLDER = 4,
/* Hack: Set this flag right before jumping into IM when we expect
Index: irc_channel.c
===================================================================
--- irc_channel.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ irc_channel.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -276,5 +276,5 @@
if (ic->irc->status & USTATUS_SHUTDOWN) {
/* Don't do anything fancy when we're shutting down anyway. */
- } else if (ic->flags & IRC_CHANNEL_TEMP) {
+ } else if (ic->flags & IRC_CHANNEL_TEMP && !(ic->flags & IRC_CHANNEL_KEEP_PLACEHOLDER)) {
irc_channel_free_soon(ic);
} else {
Index: irc_im.c
===================================================================
--- irc_im.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ irc_im.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -576,9 +576,17 @@
ic->data = c;
- topic = g_strdup_printf(
- "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!",
- c->title);
- irc_channel_set_topic(ic, topic, irc->root);
- g_free(topic);
+ if (ic->topic == NULL) {
+ /* New channel with no preset topic - make up a generic one */
+ topic = g_strdup_printf(
+ "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!",
+ c->title);
+ irc_channel_set_topic(ic, topic, irc->root);
+ } else {
+ /* Preset topic from the channel we picked */
+ topic = g_strdup(ic->topic);
+ }
+
+ g_free(c->topic);
+ c->topic = topic; /* Let groupchat borrow this pointer */
return TRUE;
@@ -600,4 +608,25 @@
c->ui_data = NULL;
irc_channel_del_user(ic, ic->irc->user, IRC_CDU_KICK, "Chatroom closed by server");
+
+ return TRUE;
+}
+
+static gboolean bee_irc_chat_placeholder_new(bee_t *bee, struct im_connection *ic, const char *handle,
+ const char *name, const char *topic)
+{
+ irc_t *irc = bee->ui_data;
+ irc_channel_t *ircc;
+ char *full_name = irc_channel_name_gen(irc, name);
+
+ ircc = irc_channel_new(irc, full_name);
+
+ set_setstr(&ircc->set, "type", "chat");
+ set_setstr(&ircc->set, "chat_type", "placeholder");
+ set_setstr(&ircc->set, "account", ic->acc->tag);
+ set_setstr(&ircc->set, "room", (char *) handle);
+
+ irc_channel_set_topic(ircc, topic, NULL);
+
+ g_free(full_name);
return TRUE;
@@ -826,8 +855,10 @@
static gboolean bee_irc_channel_chat_join(irc_channel_t *ic)
{
- char *acc_s, *room;
+ char *acc_s, *room, *chat_type;
account_t *acc;
- if (strcmp(set_getstr(&ic->set, "chat_type"), "room") != 0) {
+ chat_type = set_getstr(&ic->set, "chat_type");
+
+ if (strcmp(chat_type, "room") != 0 && strcmp(chat_type, "placeholder") != 0) {
return TRUE;
}
@@ -985,8 +1016,12 @@
struct irc_channel *ic = set->data;
+ ic->flags &= ~(IRC_CHANNEL_TEMP | IRC_CHANNEL_KEEP_PLACEHOLDER);
+
if (strcmp(value, "groupchat") == 0) {
ic->flags |= IRC_CHANNEL_TEMP;
} else if (strcmp(value, "room") == 0) {
- ic->flags &= ~IRC_CHANNEL_TEMP;
+ // beep boop
+ } else if (strcmp(value, "placeholder") == 0) {
+ ic->flags |= IRC_CHANNEL_TEMP | IRC_CHANNEL_KEEP_PLACEHOLDER;
} else {
return NULL;
@@ -1072,4 +1107,5 @@
bee_irc_chat_new,
bee_irc_chat_free,
+ bee_irc_chat_placeholder_new,
bee_irc_chat_log,
bee_irc_chat_msg,
Index: nick.c
===================================================================
--- nick.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ nick.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -368,7 +368,11 @@
if (tab['A'] == 0) {
+ /* initialize table so nonchars are mapped to themselves */
+ for (i = 0; i < sizeof(tab); i++) {
+ tab[i] = i;
+ }
+ /* replace uppercase chars with lowercase chars */
for (i = 0; nick_lc_chars[i]; i++) {
tab[(int) nick_uc_chars[i]] = nick_lc_chars[i];
- tab[(int) nick_lc_chars[i]] = nick_lc_chars[i];
}
}
Index: protocols/bee.h
===================================================================
--- protocols/bee.h (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/bee.h (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -115,4 +115,6 @@
gboolean (*chat_new)(bee_t *bee, struct groupchat *c);
gboolean (*chat_free)(bee_t *bee, struct groupchat *c);
+ gboolean (*chat_placeholder_new)(bee_t *bee, struct im_connection *ic, const char *handle,
+ const char *name, const char *topic);
/* System messages of any kind. */
gboolean (*chat_log)(bee_t *bee, struct groupchat *c, const char *text);
@@ -156,4 +158,5 @@
G_MODULE_EXPORT void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, guint32 flags,
time_t sent_at);
+G_MODULE_EXPORT void imcb_notify_email(struct im_connection *ic, char *format, ...) G_GNUC_PRINTF(2, 3);
/* bee_chat.c */
@@ -165,4 +168,6 @@
* user, too. */
G_MODULE_EXPORT struct groupchat *imcb_chat_new(struct im_connection *ic, const char *handle);
+G_MODULE_EXPORT void imcb_chat_placeholder_new(struct im_connection *ic, const char *handle, const char *name,
+ const char *topic);
G_MODULE_EXPORT void imcb_chat_name_hint(struct groupchat *c, const char *name);
G_MODULE_EXPORT void imcb_chat_free(struct groupchat *c);
Index: protocols/bee_chat.c
===================================================================
--- protocols/bee_chat.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/bee_chat.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -54,4 +54,13 @@
}
+void imcb_chat_placeholder_new(struct im_connection *ic, const char *handle, const char *name, const char *topic)
+{
+ bee_t *bee = ic->bee;
+
+ if (bee->ui->chat_placeholder_new) {
+ bee->ui->chat_placeholder_new(bee, ic, handle, name, topic);
+ }
+}
+
void imcb_chat_name_hint(struct groupchat *c, const char *name)
{
Index: protocols/bee_user.c
===================================================================
--- protocols/bee_user.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/bee_user.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -271,4 +271,30 @@
}
+void imcb_notify_email(struct im_connection *ic, char *format, ...)
+{
+ const char *handle;
+ va_list params;
+ char *msg;
+
+ if (!set_getbool(&ic->acc->set, "mail_notifications")) {
+ return;
+ }
+
+ va_start(params, format);
+ msg = g_strdup_vprintf(format, params);
+ va_end(params);
+
+ /* up to the protocol to set_add this if they want to use this */
+ handle = set_getstr(&ic->acc->set, "mail_notifications_handle");
+
+ if (handle != NULL) {
+ imcb_buddy_msg(ic, handle, msg, 0, 0);
+ } else {
+ imcb_log(ic, "%s", msg);
+ }
+
+ g_free(msg);
+}
+
void imcb_buddy_typing(struct im_connection *ic, const char *handle, uint32_t flags)
{
Index: protocols/jabber/conference.c
===================================================================
--- protocols/jabber/conference.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/jabber/conference.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -354,77 +354,87 @@
struct xt_node *subject = xt_find_node(node->children, "subject");
struct xt_node *body = xt_find_node(node->children, "body");
- struct groupchat *chat = bud ? jabber_chat_by_jid(ic, bud->bare_jid) : NULL;
- struct jabber_chat *jc = chat ? chat->data : NULL;
- char *s;
+ struct groupchat *chat = NULL;
+ struct jabber_chat *jc = NULL;
+ char *from = NULL;
+ char *nick = NULL;
+ char *final_from = NULL;
+ char *bare_jid = NULL;
+
+ from = (bud) ? bud->full_jid : xt_find_attr(node, "from");
+
+ if (from) {
+ nick = strchr(from, '/');
+ if (nick) {
+ *nick = 0;
+ }
+ chat = jabber_chat_by_jid(ic, from);
+ if (nick) {
+ *nick = '/';
+ nick++;
+ }
+ }
+
+ jc = (chat) ? chat->data : NULL;
+
+ if (!bud) {
+ struct xt_node *c;
+ char *s;
+
+ /* Try some clever stuff to find out the real JID here */
+ c = xt_find_node_by_attr(node->children, "delay", "xmlns", XMLNS_DELAY);
+
+ if (c && ((s = xt_find_attr(c, "from")) ||
+ (s = xt_find_attr(c, "from_jid")))) {
+ /* This won't be useful if it's the MUC JID */
+ if (!(jc && jabber_compare_jid(s, jc->name))) {
+ /* Hopefully this one makes more sense! */
+ bud = jabber_buddy_by_jid(ic, s, GET_BUDDY_FIRST | GET_BUDDY_CREAT);
+ }
+ }
+
+ }
if (subject && chat) {
- s = (bud && bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL;
- if (s) {
- *s = 0;
- }
- imcb_chat_topic(chat, bud ? bud->ext_jid : NULL, subject->text_len > 0 ?
- subject->text : NULL, jabber_get_timestamp(node));
- if (s) {
- *s = '/';
- }
- }
-
- if (bud == NULL || (jc && ~jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me)) {
- char *nick;
-
- if (body == NULL || body->text_len == 0) {
- /* Meh. Empty messages aren't very interesting, no matter
- how much some servers love to send them. */
- return;
- }
-
- s = xt_find_attr(node, "from"); /* pkt_message() already NULL-checked this one. */
- nick = strchr(s, '/');
- if (nick) {
- /* If this message included a resource/nick we don't know,
- we might still know the groupchat itself. */
- *nick = 0;
- chat = jabber_chat_by_jid(ic, s);
- *nick = '/';
-
- nick++;
+ char *subject_text = subject->text_len > 0 ? subject->text : NULL;
+ if (g_strcmp0(chat->topic, subject_text) != 0) {
+ bare_jid = (bud) ? jabber_get_bare_jid(bud->ext_jid) : NULL;
+ imcb_chat_topic(chat, bare_jid, subject_text,
+ jabber_get_timestamp(node));
+ g_free(bare_jid);
+ }
+ }
+
+ if (body == NULL || body->text_len == 0) {
+ /* Meh. Empty messages aren't very interesting, no matter
+ how much some servers love to send them. */
+ return;
+ }
+
+ if (chat == NULL) {
+ if (nick == NULL) {
+ imcb_log(ic, "System message from unknown groupchat %s: %s", from, body->text);
} else {
- /* message.c uses the EXACT_JID option, so bud should
- always be NULL here for bare JIDs. */
- chat = jabber_chat_by_jid(ic, s);
- }
-
- if (nick == NULL) {
- /* This is fine, the groupchat itself isn't in jd->buddies. */
- if (chat) {
- imcb_chat_log(chat, "From conference server: %s", body->text);
- } else {
- imcb_log(ic, "System message from unknown groupchat %s: %s", s, body->text);
- }
- } else {
- /* This can happen too, at least when receiving a backlog when
- just joining a channel. */
- if (chat) {
- imcb_chat_log(chat, "Message from unknown participant %s: %s", nick, body->text);
- } else {
- imcb_log(ic, "Groupchat message from unknown JID %s: %s", s, body->text);
- }
+ imcb_log(ic, "Groupchat message from unknown JID %s: %s", from, body->text);
}
return;
- } else if (chat == NULL) {
- /* How could this happen?? We could do kill( self, 11 )
- now or just wait for the OS to do it. :-) */
+ } else if (chat != NULL && bud == NULL && nick == NULL) {
+ imcb_chat_log(chat, "From conference server: %s", body->text);
return;
- }
- if (body && body->text_len > 0) {
- s = (bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL;
- if (s) {
- *s = 0;
- }
- imcb_chat_msg(chat, bud->ext_jid, body->text, 0, jabber_get_timestamp(node));
- if (s) {
- *s = '/';
- }
- }
-}
+ } else if (jc && jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me) {
+ /* exclude self-messages since they would get filtered out
+ * but not the ones in the backlog */
+ return;
+ }
+
+ if (bud && jc && bud != jc->me) {
+ bare_jid = jabber_get_bare_jid(bud->ext_jid ? bud->ext_jid : bud->full_jid);
+ final_from = bare_jid;
+ } else {
+ final_from = nick;
+ }
+
+ imcb_chat_msg(chat, final_from, body->text, 0, jabber_get_timestamp(node));
+
+ g_free(bare_jid);
+}
Index: protocols/jabber/hipchat.c
===================================================================
--- protocols/jabber/hipchat.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/jabber/hipchat.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -27,7 +27,8 @@
{
struct jabber_data *jd = ic->proto_data;
- char *sep, *jid;
+ char *sep, *jid, *muc_host;
jid = xt_find_attr(node, "jid");
+ muc_host = xt_find_attr(node, "muc_host");
sep = strchr(jid, '/');
@@ -48,5 +49,6 @@
if (!jabber_get_roster(ic) ||
!jabber_iq_disco_server(ic) ||
- !jabber_get_hipchat_profile(ic)) {
+ !jabber_get_hipchat_profile(ic) ||
+ !jabber_iq_disco_muc(ic, muc_host)) {
return XT_ABORT;
}
@@ -92,2 +94,49 @@
}
+
+int jabber_iq_disco_muc(struct im_connection *ic, char *muc_server)
+{
+ struct xt_node *node;
+ int st;
+
+ imcb_log(ic, "Fetching MUC list");
+
+ node = xt_new_node("query", NULL, NULL);
+ xt_add_attr(node, "xmlns", XMLNS_DISCO_ITEMS);
+ node = jabber_make_packet("iq", "get", muc_server, node);
+
+ jabber_cache_add(ic, node, jabber_parse_muc_list);
+ st = jabber_write_packet(ic, node);
+
+ return st;
+}
+
+xt_status jabber_parse_muc_list(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
+{
+ struct xt_node *query, *c;
+
+ if (!(query = xt_find_node(node->children, "query"))) {
+ imcb_log(ic, "Warning: Received NULL MUC list packet");
+ return XT_HANDLED;
+ }
+
+ c = query->children;
+ while ((c = xt_find_node(c, "item"))) {
+ struct xt_node *c2;
+ char *topic = NULL;
+ char *jid = xt_find_attr(c, "jid");
+ char *name = xt_find_attr(c, "name");
+
+ imcb_log(ic, "Debug: adding MUC to channel list: %s - '%s'", jid, name);
+
+ if ((c2 = xt_find_node_by_attr(c->children, "x", "xmlns", XMLNS_HIPCHAT_MUC)) &&
+ (c2 = xt_find_node(c2->children, "topic"))) {
+ topic = c2->text;
+ }
+
+ imcb_chat_placeholder_new(ic, jid, name, topic);
+ c = c->next;
+ }
+ return XT_HANDLED;
+
+}
Index: protocols/jabber/iq.c
===================================================================
--- protocols/jabber/iq.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/jabber/iq.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -27,4 +27,5 @@
static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
static xt_status jabber_iq_display_vcard(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
+static xt_status jabber_gmail_handle_new(struct im_connection *ic, struct xt_node *node);
xt_status jabber_pkt_iq(struct xt_node *node, gpointer data)
@@ -141,4 +142,8 @@
(strcmp(s, XMLNS_SI) == 0)) {
return jabber_si_handle_request(ic, node, c);
+ } else if ((c = xt_find_node(node->children, "new-mail")) &&
+ (s = xt_find_attr(c, "xmlns")) &&
+ (strcmp(s, XMLNS_GMAILNOTIFY) == 0)) {
+ return jabber_gmail_handle_new(ic, node);
} else if (!(c = xt_find_node(node->children, "query")) ||
!(s = xt_find_attr(c, "xmlns"))) {
@@ -342,4 +347,7 @@
return XT_ABORT;
}
+ if (jd->flags & JFLAG_GMAILNOTIFY && node == NULL) {
+ jabber_iq_query_server(ic, jd->server, XMLNS_DISCO_INFO);
+ }
} else if ((jd->flags & (JFLAG_WANT_BIND | JFLAG_WANT_SESSION)) == 0) {
if (!jabber_get_roster(ic)) {
@@ -369,4 +377,23 @@
return st;
+}
+
+xt_status jabber_iq_query_gmail(struct im_connection *ic);
+
+static xt_status jabber_gmail_handle_new(struct im_connection *ic, struct xt_node *node)
+{
+ struct xt_node *response;
+ struct jabber_data *jd = ic->proto_data;
+
+ response = jabber_make_packet("iq", "result", g_strdup_printf("%s@%s", jd->username, jd->server), NULL);
+
+ jabber_cache_add(ic, response, NULL);
+ if (!jabber_write_packet(ic, response)) {
+ return XT_ABORT;
+ }
+
+ jabber_iq_query_gmail(ic);
+
+ return XT_HANDLED;
}
@@ -710,4 +737,32 @@
}
+xt_status jabber_iq_parse_gmail(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
+
+xt_status jabber_iq_query_gmail(struct im_connection *ic)
+{
+ struct xt_node *node, *query;
+ struct jabber_data *jd = ic->proto_data;
+
+ node = xt_new_node("query", NULL, NULL);
+ xt_add_attr(node, "xmlns", XMLNS_GMAILNOTIFY);
+ if (jd->gmail_time) {
+ char *formatted = g_strdup_printf("%" G_GUINT64_FORMAT, (jd->gmail_time + 1));
+ xt_add_attr(node, "newer-than-time", formatted);
+ g_free(formatted);
+ }
+ if (jd->gmail_tid) {
+ xt_add_attr(node, "newer-than-tid", jd->gmail_tid);
+ }
+
+ if (!(query = jabber_make_packet("iq", "get", jd->me, node))) {
+ imcb_log(ic, "WARNING: Couldn't generate server query");
+ xt_free_node(node);
+ }
+
+ jabber_cache_add(ic, query, jabber_iq_parse_gmail);
+
+ return jabber_write_packet(ic, query) ? XT_HANDLED : XT_ABORT;
+}
+
xt_status jabber_iq_parse_server_features(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
@@ -729,4 +784,61 @@
return jabber_write_packet(ic, query) ? XT_HANDLED : XT_ABORT;
+}
+
+xt_status jabber_iq_parse_gmail(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
+{
+ struct xt_node *c;
+ struct jabber_data *jd = ic->proto_data;
+ char *xmlns, *from;
+ guint64 l_time = 0;
+ char *tid = NULL;
+ int max = 0;
+
+ if (!(c = xt_find_node(node->children, "mailbox")) ||
+ !(from = xt_find_attr(node, "from")) ||
+ !(xmlns = xt_find_attr(c, "xmlns")) ||
+ (g_strcmp0(xmlns, XMLNS_GMAILNOTIFY) != 0)) {
+ imcb_log(ic, "WARNING: Received incomplete mailbox packet for gmail notify");
+ return XT_HANDLED;
+ }
+
+ max = set_getint(&ic->acc->set, "mail_notifications_limit");
+ c = c->children;
+
+ while ((max-- > 0) && (c = xt_find_node(c, "mail-thread-info"))) {
+ struct xt_node *s;
+ char *subject = "";
+ char *sender = "";
+ guint64 t_time;
+
+ t_time = g_ascii_strtoull(xt_find_attr(c, "date"), NULL, 10);
+ if (t_time && t_time > l_time) {
+ l_time = t_time;
+ tid = xt_find_attr(c, "tid");
+ }
+
+ if ((s = xt_find_node(c->children, "senders")) &&
+ (s = xt_find_node_by_attr(s->children, "sender", "unread", "1"))) {
+ sender = xt_find_attr(s, "name");
+ }
+
+ if ((s = xt_find_node(c->children, "subject")) && s->text) {
+ subject = s->text;
+ }
+
+ imcb_notify_email(ic, "New mail from %s: %s", sender, subject);
+
+ c = c->next;
+ }
+
+ if (l_time && (!jd->gmail_time || l_time > jd->gmail_time)) {
+ jd->gmail_time = l_time;
+ if (tid) {
+ g_free(jd->gmail_tid);
+ jd->gmail_tid = g_strdup(tid);
+ }
+ }
+
+ return XT_HANDLED;
}
@@ -781,4 +893,17 @@
c = c->next;
}
+
+ if (jd->flags & JFLAG_GMAILNOTIFY) {
+ /* search for gmail notification feature */
+ c = xt_find_node(node->children, "query");
+ c = c->children;
+ while ((c = xt_find_node(c, "feature"))) {
+ if (strcmp(xt_find_attr(c, "var"), XMLNS_GMAILNOTIFY) == 0) {
+ jabber_iq_query_gmail(ic);
+ }
+ c = c->next;
+ }
+ }
+
} else if (strcmp(xmlns, XMLNS_BYTESTREAMS) == 0) {
char *host, *jid, *port_s;
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/jabber/jabber.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -100,5 +100,14 @@
s = set_add(&acc->set, "xmlconsole", "false", set_eval_bool, acc);
+
+ s = set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
s->flags |= ACC_SET_OFFLINE_ONLY;
+
+ /* changing this is rarely needed so keeping it secret */
+ s = set_add(&acc->set, "mail_notifications_limit", "5", set_eval_int, acc);
+ s->flags |= SET_HIDDEN_DEFAULT;
+
+ s = set_add(&acc->set, "mail_notifications_handle", NULL, NULL, acc);
+ s->flags |= ACC_SET_OFFLINE_ONLY | SET_NULL_OK;
acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE |
@@ -260,4 +269,12 @@
}
+ if (set_getbool(&acc->set, "mail_notifications")) {
+ /* It's gmail specific, but it checks for server support before enabling it */
+ jd->flags |= JFLAG_GMAILNOTIFY;
+ if (set_getstr(&acc->set, "mail_notifications_handle")) {
+ imcb_add_buddy(ic, set_getstr(&acc->set, "mail_notifications_handle"), NULL);
+ }
+ }
+
jabber_generate_id_hash(jd);
}
@@ -334,4 +351,5 @@
g_free(jd->away_message);
g_free(jd->internal_jid);
+ g_free(jd->gmail_tid);
g_free(jd->username);
g_free(jd->me);
Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/jabber/jabber.h (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -46,4 +46,5 @@
JFLAG_XMLCONSOLE = 64, /* If the user added an xmlconsole buddy. */
JFLAG_STARTTLS_DONE = 128, /* If a plaintext session was converted to TLS. */
+ JFLAG_GMAILNOTIFY = 256, /* If gmail notification is enabled */
JFLAG_GTALK = 0x100000, /* Is Google Talk, as confirmed by iq discovery */
@@ -102,4 +103,6 @@
const struct jabber_away_state *away_state;
char *away_message;
+ guint64 gmail_time;
+ char *gmail_tid;
md5_state_t cached_id_prefix;
@@ -224,4 +227,5 @@
#define XMLNS_DELAY "urn:xmpp:delay" /* XEP-0203 */
#define XMLNS_XDATA "jabber:x:data" /* XEP-0004 */
+#define XMLNS_GMAILNOTIFY "google:mail:notify" /* Not a XEP */
#define XMLNS_CHATSTATES "http://jabber.org/protocol/chatstates" /* XEP-0085 */
#define XMLNS_DISCO_INFO "http://jabber.org/protocol/disco#info" /* XEP-0030 */
@@ -239,4 +243,5 @@
#define XMLNS_HIPCHAT "http://hipchat.com"
#define XMLNS_HIPCHAT_PROFILE "http://hipchat.com/protocol/profile"
+#define XMLNS_HIPCHAT_MUC "http://hipchat.com/protocol/muc#room"
/* jabber.c */
@@ -249,4 +254,5 @@
int jabber_get_roster(struct im_connection *ic);
int jabber_get_vcard(struct im_connection *ic, char *bare_jid);
+int jabber_iq_disco_muc(struct im_connection *ic, char *muc_server);
int jabber_add_to_roster(struct im_connection *ic, const char *handle, const char *name, const char *group);
int jabber_remove_from_roster(struct im_connection *ic, char *handle);
@@ -312,4 +318,5 @@
void jabber_error_free(struct jabber_error *err);
gboolean jabber_set_me(struct im_connection *ic, const char *me);
+char *jabber_get_bare_jid(char *jid);
extern const struct jabber_away_state jabber_away_state_list[];
@@ -351,4 +358,5 @@
xt_status jabber_parse_hipchat_profile(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
xt_status hipchat_handle_success(struct im_connection *ic, struct xt_node *node);
+xt_status jabber_parse_muc_list(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
#endif
Index: protocols/jabber/jabber_util.c
===================================================================
--- protocols/jabber/jabber_util.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/jabber/jabber_util.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -820,2 +820,18 @@
return TRUE;
}
+
+/* Returns new reference! g_free() afterwards. */
+char *jabber_get_bare_jid(char *jid)
+{
+ char *s = NULL;
+
+ if (jid == NULL) {
+ return NULL;
+ }
+
+ if ((s = strchr(jid, '/'))) {
+ return g_strndup(jid, s - jid);
+ } else {
+ return g_strdup(jid);
+ }
+}
Index: protocols/jabber/presence.c
===================================================================
--- protocols/jabber/presence.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/jabber/presence.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -181,4 +181,20 @@
}
+static char *choose_priority(struct im_connection *ic)
+{
+ struct jabber_data *jd = ic->proto_data;
+ char *prio = set_getstr(&ic->acc->set, "priority");
+
+ if (jd->away_state->code != NULL) {
+ int new_prio = (atoi(prio) - 5);
+ if (new_prio < 0) {
+ new_prio = 0;
+ }
+ return g_strdup_printf("%d", new_prio);
+ }
+
+ return g_strdup(prio);
+}
+
/* Whenever presence information is updated, call this function to inform the
server. */
@@ -189,7 +205,8 @@
GSList *l;
int st;
+ char *prio = choose_priority(ic);
node = jabber_make_packet("presence", NULL, NULL, NULL);
- xt_add_child(node, xt_new_node("priority", set_getstr(&ic->acc->set, "priority"), NULL));
+ xt_add_child(node, xt_new_node("priority", prio, NULL));
if (jd->away_state) {
xt_add_child(node, xt_new_node("show", jd->away_state->code, NULL));
@@ -222,4 +239,5 @@
xt_free_node(node);
+ g_free(prio);
return st;
}
Index: protocols/msn/msn.c
===================================================================
--- protocols/msn/msn.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/msn/msn.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -46,5 +46,9 @@
s->flags |= ACC_SET_OFFLINE_ONLY;
- set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
+ s = set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
+ s->flags |= ACC_SET_OFFLINE_ONLY;
+
+ s = set_add(&acc->set, "mail_notifications_handle", NULL, NULL, acc);
+ s->flags |= ACC_SET_OFFLINE_ONLY | SET_NULL_OK;
acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE |
@@ -82,4 +86,8 @@
msn_ns_connect(ic, server,
set_getint(&ic->acc->set, "port"));
+
+ if (set_getbool(&acc->set, "mail_notifications") && set_getstr(&acc->set, "mail_notifications_handle")) {
+ imcb_add_buddy(ic, set_getstr(&acc->set, "mail_notifications_handle"), NULL);
+ }
}
Index: protocols/msn/ns.c
===================================================================
--- protocols/msn/ns.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/msn/ns.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -394,7 +394,7 @@
if (inbox && folders) {
- imcb_log(ic,
- "INBOX contains %s new messages, plus %s messages in other folders.", inbox,
- folders);
+ imcb_notify_email(ic,
+ "INBOX contains %s new messages, plus %s messages in other folders.", inbox,
+ folders);
}
@@ -408,6 +408,5 @@
if (from && fromname) {
- imcb_log(ic, "Received an e-mail message from %s <%s>.", fromname,
- from);
+ imcb_notify_email(ic, "Received an e-mail message from %s <%s>.", fromname, from);
}
Index: protocols/purple/purple.c
===================================================================
--- protocols/purple/purple.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/purple/purple.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -238,4 +238,7 @@
s = set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
s->flags |= ACC_SET_OFFLINE_ONLY;
+
+ s = set_add(&acc->set, "mail_notifications_handle", NULL, NULL, acc);
+ s->flags |= ACC_SET_OFFLINE_ONLY | SET_NULL_OK;
}
@@ -332,4 +335,8 @@
purple_account_set_enabled(pd->account, "BitlBee", TRUE);
+
+ if (set_getbool(&acc->set, "mail_notifications") && set_getstr(&acc->set, "mail_notifications_handle")) {
+ imcb_add_buddy(ic, set_getstr(&acc->set, "mail_notifications_handle"), NULL);
+ }
}
@@ -1255,5 +1262,5 @@
struct im_connection *ic = purple_ic_by_gc(gc);
- imcb_log(ic, "Received e-mail from %s for %s: %s <%s>", from, to, subject, url);
+ imcb_notify_email(ic, "Received e-mail from %s for %s: %s <%s>", from, to, subject, url);
return NULL;
Index: protocols/yahoo/yahoo.c
===================================================================
--- protocols/yahoo/yahoo.c (revision d30444594e95471bb8da46789d791af53e1769f3)
+++ protocols/yahoo/yahoo.c (revision c720890fe4fa7719221d52221fa85cdac5e00a1b)
@@ -123,5 +123,11 @@
static void byahoo_init(account_t *acc)
{
- set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
+ set_t *s;
+
+ s = set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
+ s->flags |= ACC_SET_OFFLINE_ONLY;
+
+ s = set_add(&acc->set, "mail_notifications_handle", NULL, NULL, acc);
+ s->flags |= ACC_SET_OFFLINE_ONLY | SET_NULL_OK;
acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE;
@@ -145,4 +151,8 @@
yd->y2_id = yahoo_init(acc->user, acc->pass);
yahoo_login(yd->y2_id, yd->current_status);
+
+ if (set_getbool(&acc->set, "mail_notifications") && set_getstr(&acc->set, "mail_notifications_handle")) {
+ imcb_add_buddy(ic, set_getstr(&acc->set, "mail_notifications_handle"), NULL);
+ }
}
@@ -950,10 +960,8 @@
struct im_connection *ic = byahoo_get_ic_by_id(id);
- if (!set_getbool(&ic->acc->set, "mail_notifications")) {
- ; /* The user doesn't care. */
- } else if (from && subj) {
- imcb_log(ic, "Received e-mail message from %s with subject `%s'", from, subj);
+ if (from && subj) {
+ imcb_notify_email(ic, "Received e-mail message from %s with subject `%s'", from, subj);
} else if (cnt > 0) {
- imcb_log(ic, "Received %d new e-mails", cnt);
+ imcb_notify_email(ic, "Received %d new e-mails", cnt);
}
}