diff --git a/instantbird/content/instantbird/joinchat.js b/instantbird/content/instantbird/joinchat.js
--- a/instantbird/content/instantbird/joinchat.js
+++ b/instantbird/content/instantbird/joinchat.js
@@ -42,43 +42,119 @@ var joinChat = {
this.pcs = Components.classes["@instantbird.org/purple/core;1"]
.getService(Ci.purpleICoreService);
this.buildAccountList();
},
buildAccountList: function jc_buildAccountList() {
var accountList = document.getElementById("accountlist");
for (let acc in this.getAccounts()) {
- if (!acc.connected)
+ if (!acc.connected || !acc.canJoinChat)
continue;
var proto = acc.protocol;
- if (proto.id != "prpl-irc")
- continue;
var item = accountList.appendItem(acc.name, acc.id, proto.name);
item.setAttribute("image", proto.iconBaseURI + "icon.png");
item.setAttribute("class", "menuitem-iconic");
+ item.account = acc;
}
if (!accountList.itemCount) {
document.getElementById("joinChatDialog").cancelDialog();
- throw "No connected IRC account!";
+ throw "No connected MUC enabled account!";
}
accountList.selectedIndex = 0;
},
- getValue: function jc_getValue(aId) {
- var elt = document.getElementById(aId);
- return elt.value;
+ onAccountSelect: function jc_onAccountSelect() {
+ let ab = document.getElementById("separatorRow1");
+ while (ab.nextSibling && ab.nextSibling.id != "separatorRow2")
+ ab.parentNode.removeChild(ab.nextSibling);
+
+ let acc = document.getElementById("accountlist").selectedItem.account;
+ let sep = document.getElementById("separatorRow2");
+ let defaultValues = acc.getChatRoomDefaultFieldValues();
+ joinChat._values = defaultValues;
+ joinChat._fields = [];
+ joinChat._account = acc;
+
+ let protoId = acc.protocol.id;
+ document.getElementById("autojoin").visible =
+ protoId == "prpl-irc" || protoId == "prpl-jabber" ||
+ protoId == "prpl-gtalk";
+
+ for (let field in getIter(acc.getChatRoomFields())) {
+ let row = document.createElement("row");
+
+ let label = document.createElement("label");
+ let text = field.label;
+ let match = /_(.)/(text);
+ if (match) {
+ label.setAttribute("accesskey", match[1]);
+ text = text.replace(/_/, "");
+ }
+ label.setAttribute("value", text);
+ label.setAttribute("control", "field-" + field.identifier);
+ row.appendChild(label);
+
+ let textbox = document.createElement("textbox");
+ textbox.setAttribute("id", "field-" + field.identifier);
+ let val = defaultValues.getValue(field.identifier);
+ if (val)
+ textbox.setAttribute("value", val);
+ if (field.type == Ci.purpleIChatRoomField.TYPE_PASSWORD)
+ textbox.setAttribute("type", "password");
+ else if (field.type == Ci.purpleIChatRoomField.TYPE_INT) {
+ textbox.setAttribute("type", "number");
+ textbox.setAttribute("min", field.min);
+ textbox.setAttribute("max", field.max);
+ }
+ row.appendChild(textbox);
+
+ if (!field.required) {
+ label = document.createElement("label");
+ text = document.getElementById("optionalcolumn")
+ .getAttribute("labeltxt");
+ label.setAttribute("value", text);
+ row.appendChild(label);
+ }
+
+ sep.parentNode.insertBefore(row, sep);
+ joinChat._fields.push({field: field, textbox: textbox});
+ }
+
+ window.sizeToContent();
},
join: function jc_join() {
- var account = this.pcs.getAccountById(this.getValue("accountlist"));
- var name = this.getValue("name")
- var conv = account.joinChat(name);
+ let values = joinChat._values;
+ for each (let field in joinChat._fields) {
+ let val = field.textbox.value;
+ if (!val && field.field.required) {
+ field.textbox.focus();
+ //FIXME: why isn't the return false enough?
+ throw "Some required fields are empty!";
+ return false;
+ }
+ if (val)
+ values.setValue(field.field.identifier, val);
+ }
- if (document.getElementById("autojoin").checked) {
+ joinChat._account.joinChat(values);
+ return true;
+
+ let protoId = acc.protocol.id;
+ if ((protoId == "prpl-irc" || protoId == "prpl-jabber" ||
+ protoId == "prpl-gtalk") &&
+ document.getElementById("autojoin").checked) {
+ let name;
+ if (protoId == "prpl-irc")
+ name = values.getValue("channel");
+ else
+ name = values.getValue("room") + "@" +
+ values.getValue("server") + "/" + values.getValue("nick");
+
var prefBranch = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService)
.getBranch("messenger.account." + account.id + ".");
var autojoin = [ ];
if (prefBranch.prefHasUserValue(autoJoinPref)) {
var prefValue = prefBranch.getCharPref(autoJoinPref);
if (prefValue)
autojoin = prefValue.split(",");
@@ -89,17 +165,17 @@ var joinChat = {
prefBranch.setCharPref(autoJoinPref, autojoin.join(","));
}
}
// if the conversation is being created, |conv| will be null
// here. The new-conversation notification should be used to focus
// it when done. If it is already opened, we should focus it now.
if (!conv)
- return;
+ return true;
Components.utils.import("resource://app/modules/imWindows.jsm");
Conversations.focusConversation(conv);
},
getAccounts: function jc_getAccounts() {
return getIter(this.pcs.getAccounts());
}
diff --git a/instantbird/content/instantbird/joinchat.xul b/instantbird/content/instantbird/joinchat.xul
--- a/instantbird/content/instantbird/joinchat.xul
+++ b/instantbird/content/instantbird/joinchat.xul
@@ -52,27 +52,31 @@
ondialogaccept="joinChat.join()">
+
+
+
+
+
+
+
+
-
-
-
-
-
+
diff --git a/purple/purplexpcom/public/purpleIAccount.idl b/purple/purplexpcom/public/purpleIAccount.idl
--- a/purple/purplexpcom/public/purpleIAccount.idl
+++ b/purple/purplexpcom/public/purpleIAccount.idl
@@ -36,35 +36,67 @@
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
#include "purpleIProtocol.idl"
#include "purpleIConversation.idl"
#include "purpleIProxy.idl"
/*
+ * Used to join chat rooms.
+ */
+
+[ptr] native GHashTablePtr(GHashTable);
+
+[scriptable, uuid(ea7ab156-d25e-46cc-93ef-29f77b3c0795)]
+interface purpleIChatRoomFieldValues: nsISupports {
+ AUTF8String getValue(in AUTF8String aIdentifier);
+ void setValue(in AUTF8String aIdentifier, in AUTF8String aValue);
+
+ [noscript] readonly attribute GHashTablePtr hashTable;
+};
+
+[scriptable, uuid(19dff981-b125-4a70-bc1a-efc783d07137)]
+interface purpleIChatRoomField: nsISupports {
+ readonly attribute AUTF8String label;
+ readonly attribute AUTF8String identifier;
+ readonly attribute boolean required;
+
+ const short TYPE_TEXT = 0;
+ const short TYPE_PASSWORD = 1;
+ const short TYPE_INT = 2;
+
+ readonly attribute short type;
+ readonly attribute long min;
+ readonly attribute long max;
+};
+
+/*
* This is a proxy to libpurple PurpleAccount
*/
-
[scriptable, uuid(3c01ec75-6504-40df-af18-b8dc402c75a6)]
interface purpleIAccount: nsISupports {
void connect();
void disconnect();
/* Cancel the timer that automatically reconnects the account that were
disconnected with a non fatal error */
void cancelReconnection();
purpleIConversation createConversation(in AUTF8String aName);
+ readonly attribute boolean canJoinChat;
+ nsISimpleEnumerator getChatRoomFields();
+ purpleIChatRoomFieldValues getChatRoomDefaultFieldValues();
/*
* Create a new chat conversation if it doesn't already exist.
* Returns the conversation if it already existed, null otherwise
*/
- purpleIConversation joinChat(in AUTF8String aName);
+ purpleIConversation joinChat(in purpleIChatRoomFieldValues aComponents);
+
readonly attribute AUTF8String name;
readonly attribute AUTF8String id;
readonly attribute purpleIProtocol protocol;
attribute boolean autoLogin;
/* This is the value when the preference firstConnectionState is not set.
It indicates that the account has already been successfully connected at
diff --git a/purple/purplexpcom/src/purpleAccount.cpp b/purple/purplexpcom/src/purpleAccount.cpp
--- a/purple/purplexpcom/src/purpleAccount.cpp
+++ b/purple/purplexpcom/src/purpleAccount.cpp
@@ -31,17 +31,19 @@
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "purpleAccount.h"
+#include "purpleClassInfo.h"
#include "purpleCoreService.h"
+#include "purpleGListEnumerator.h"
#include "purpleUnknownProtocol.h"
#include "purpleStorage.h"
#include
#include
#include
#include
#include
#include
@@ -69,16 +71,164 @@ NS_IMPL_ISUPPORTS1_CI(purpleAccount, pur
#ifdef PR_LOGGING
//
// NSPR_LOG_MODULES=purpleAccount:5
//
static PRLogModuleInfo *gPurpleAccountLog = nsnull;
#endif
#define LOG(args) PR_LOG(gPurpleAccountLog, PR_LOG_DEBUG, args)
+
+class purpleChatRoomField : public purpleIChatRoomField,
+ public nsIClassInfo
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICLASSINFO
+ NS_DECL_PURPLEICHATROOMFIELD
+
+ purpleChatRoomField() : mType(-1) {}
+ void Init(const proto_chat_entry *aChatRoomField)
+ {
+ mType =
+ aChatRoomField->is_int ? (PRInt32) purpleIChatRoomField::TYPE_INT :
+ aChatRoomField->secret ? (PRInt32) purpleIChatRoomField::TYPE_PASSWORD :
+ (PRInt32) purpleIChatRoomField::TYPE_TEXT;
+ mLabel = aChatRoomField->label;
+ mIdentifier = aChatRoomField->identifier;
+ mRequired = aChatRoomField->required;
+ mMin = aChatRoomField->min;
+ mMax = aChatRoomField->max;
+ }
+
+private:
+ ~purpleChatRoomField() {}
+
+protected:
+ /* additional members */
+ PRInt32 mType;
+ PRInt32 mMin, mMax;
+ nsCString mLabel;
+ nsCString mIdentifier;
+ PRPackedBool mRequired;
+};
+
+PURPLE_IMPL_ISUPPORTS1_CI(purpleChatRoomField, purpleIChatRoomField)
+
+#define PURPLE_IMPL_GETFIELDVALUE(aType, aName, aStar) \
+ NS_IMETHODIMP purpleChatRoomField::Get##aName(aType a##aName) \
+ { \
+ NS_ENSURE_TRUE(mType != -1, NS_ERROR_NOT_INITIALIZED); \
+ \
+ aStar a##aName = m##aName; \
+ return NS_OK; \
+ }
+
+/* readonly attribute AUTF8String label; */
+PURPLE_IMPL_GETFIELDVALUE(nsACString &, Label, )
+
+/* readonly attribute AUTF8String identifier; */
+PURPLE_IMPL_GETFIELDVALUE(nsACString &, Identifier, )
+
+/* readonly attribute boolean required; */
+PURPLE_IMPL_GETFIELDVALUE(PRBool *, Required, *)
+
+/* readonly attribute short type; */
+PURPLE_IMPL_GETFIELDVALUE(PRInt16 *, Type, *)
+
+/* readonly attribute long min; */
+PURPLE_IMPL_GETFIELDVALUE(PRInt32 *, Min, *)
+
+/* readonly attribute long max; */
+PURPLE_IMPL_GETFIELDVALUE(PRInt32 *, Max, *)
+
+#define MAX_KEYS 8
+
+class purpleChatRoomFieldValues : public purpleIChatRoomFieldValues,
+ public nsIClassInfo
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICLASSINFO
+ NS_DECL_PURPLEICHATROOMFIELDVALUES
+
+ purpleChatRoomFieldValues(GHashTable *aHashTable) :
+ mHashTable(aHashTable),
+ mKeyCount(0) {
+ }
+
+private:
+ ~purpleChatRoomFieldValues() {
+ if (NS_LIKELY(mHashTable))
+ g_hash_table_destroy(mHashTable);
+
+ while (mKeyCount)
+ g_free(mKeys[--mKeyCount]);
+ }
+
+protected:
+ /* additional members */
+ GHashTable *mHashTable;
+
+ PRInt32 mKeyCount;
+ gchar *mKeys[MAX_KEYS];
+};
+
+PURPLE_IMPL_ISUPPORTS1_CI(purpleChatRoomFieldValues, purpleIChatRoomFieldValues)
+
+/* AUTF8String getValue (in AUTF8String aIdentifier); */
+NS_IMETHODIMP
+purpleChatRoomFieldValues::GetValue(const nsACString & aIdentifier,
+ nsACString & aResult)
+{
+ if (NS_UNLIKELY(!mHashTable)) {
+ aResult.Truncate();
+ return NS_OK;
+ }
+
+ aResult =
+ static_cast(g_hash_table_lookup(mHashTable,
+ PromiseFlatCString(aIdentifier).get()));
+ return NS_OK;
+}
+
+/* void setValue (in AUTF8String aIdentifier, in AUTF8String aValue); */
+NS_IMETHODIMP
+purpleChatRoomFieldValues::SetValue(const nsACString & aIdentifier,
+ const nsACString & aValue)
+{
+ if (NS_UNLIKELY(!mHashTable)) {
+ mHashTable = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
+ }
+
+ PromiseFlatCString identifier(aIdentifier);
+ char *key = const_cast(identifier.get());
+ char *value = g_strdup(PromiseFlatCString(aValue).get());
+ printf("key = %s, value = %s\n", key, value);
+
+ if (!g_hash_table_lookup(mHashTable, key)) {
+ key = g_strdup(key);
+ if (mKeyCount < MAX_KEYS)
+ mKeys[mKeyCount++] = key;
+ // If we have already MAX_KEYS keys, we will leak, but something
+ // is already seriously wrong anyway...
+ }
+ g_hash_table_insert(mHashTable, key, value);
+
+ return NS_OK;
+}
+
+/* [noscript] readonly attribute GHashTablePtr hashTable; */
+NS_IMETHODIMP
+purpleChatRoomFieldValues::GetHashTable(GHashTable * *aHashTable)
+{
+ *aHashTable = mHashTable;
+ return NS_OK;
+}
+
nsCOMPtr purpleAccount::sSavePrefsTimer;
PRUint32 purpleAccount::sAutoLoginsPending = 0;
purpleAccount::purpleAccount()
: mAccount(NULL),
mHasValidProtocol(PR_FALSE),
mConnectionErrorReason((PurpleConnectionError)NO_ERROR),
mReconnectAttempts(0),
@@ -659,39 +809,102 @@ NS_IMETHODIMP purpleAccount::CreateConve
purpleIConversation *result = (purpleIConversation *)conv->ui_data;
NS_ENSURE_TRUE(result, NS_ERROR_NOT_INITIALIZED);
NS_ADDREF(*aResult = result);
return NS_OK;
}
+/* nsISimpleEnumerator getChatRoomFields (); */
+NS_IMETHODIMP purpleAccount::GetChatRoomFields(nsISimpleEnumerator **aResult)
+{
+ PURPLE_ENSURE_INIT(mProtocol && mAccount);
+ PurpleConnection *gc = purple_account_get_connection(mAccount);
+ NS_ENSURE_TRUE(gc, NS_ERROR_FAILURE);
+
+ PurplePluginProtocolInfo *prplInfo;
+ nsresult rv = mProtocol->GetInfo(&prplInfo);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ purpleGListEnumerator *enumerator = new purpleGListEnumerator();
+ enumerator->Init(prplInfo->chat_info(gc),
+ purpleTypeToInterface);
+
+ NS_ADDREF(*aResult = enumerator);
+ return NS_OK;
+}
+
+/* readonly attribute boolean canJoinChat; */
+NS_IMETHODIMP purpleAccount::GetCanJoinChat(PRBool *aCanJoinChat)
+{
+ PURPLE_ENSURE_INIT(mProtocol);
+
+ PurplePluginProtocolInfo *prplInfo;
+ nsresult rv = mProtocol->GetInfo(&prplInfo);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ *aCanJoinChat =
+ prplInfo->join_chat && prplInfo->chat_info && prplInfo->chat_info_defaults;
+ return NS_OK;
+}
+
+/* purpleIChatRoomFieldValues getChatRoomDefaultFieldValues (); */
+NS_IMETHODIMP purpleAccount::GetChatRoomDefaultFieldValues(purpleIChatRoomFieldValues **aResult)
+{
+ PURPLE_ENSURE_INIT(mProtocol && mAccount);
+ PurpleConnection *gc = purple_account_get_connection(mAccount);
+ NS_ENSURE_TRUE(gc, NS_ERROR_FAILURE);
+
+ PurplePluginProtocolInfo *prplInfo;
+ nsresult rv = mProtocol->GetInfo(&prplInfo);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ NS_ENSURE_TRUE(prplInfo->chat_info_defaults, NS_ERROR_UNEXPECTED);
+ GHashTable *hashTable = prplInfo->chat_info_defaults(gc, NULL);
+ NS_ADDREF(*aResult = new purpleChatRoomFieldValues(hashTable));
+ return NS_OK;
+}
+
+/* purpleIConversation joinChat (in purpleIChatRoomFieldValues aComponents); */
+NS_IMETHODIMP purpleAccount::JoinChat(purpleIChatRoomFieldValues *aComponents,
+ purpleIConversation **aResult)
/* purpleIConversation joinChat (in AUTF8String aName); */
-NS_IMETHODIMP purpleAccount::JoinChat(const nsACString& aName,
- purpleIConversation **aResult)
+// NS_IMETHODIMP purpleAccount::JoinChat(const nsACString& aName,
+// purpleIConversation **aResult)
{
+ NS_ENSURE_TRUE(aComponents, NS_ERROR_INVALID_ARG);
+
PURPLE_ENSURE_INIT(mAccount);
PurpleConnection *gc = purple_account_get_connection(mAccount);
NS_ENSURE_TRUE(gc, NS_ERROR_FAILURE);
+ GHashTable *components;
+ nsresult rv = aComponents->GetHashTable(&components);
+ NS_ENSURE_SUCCESS(rv, rv);
+ /*
PromiseFlatCString flatName(aName);
GHashTable *components = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_insert(components, const_cast("channel"),
const_cast(flatName.get()));
+ */
serv_join_chat(gc, components);
- g_hash_table_destroy(components);
+/* FIXME flatname
PurpleConversation *conv =
purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, flatName.get(), mAccount);
if (conv) {
purpleIConversation *result = (purpleIConversation *)conv->ui_data;
NS_ENSURE_TRUE(result, NS_ERROR_NOT_INITIALIZED);
NS_ADDREF(*aResult = result);
return NS_OK;
}
+*/
*aResult = nsnull;
return NS_OK;
}
/* readonly attribute AUTF8String name; */
NS_IMETHODIMP purpleAccount::GetName(nsACString& aName)
{