Skip to content

Commit 3bd815e

Browse files
authored
Merge pull request #2190 from profanity-im/fix/1782
feat(muc): Support XMPP URI 'join' query type in `/join`
2 parents a359499 + 75c4a42 commit 3bd815e

4 files changed

Lines changed: 135 additions & 3 deletions

File tree

src/command/cmd_funcs.c

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3540,6 +3540,51 @@ cmd_serversoftware(ProfWin* window, const char* const command, gchar** args)
35403540
return TRUE;
35413541
}
35423542

3543+
static gboolean
3544+
_xmpp_uri_parse_join(const gchar* uri, gchar** out_room, gchar** out_password)
3545+
{
3546+
if (g_ascii_strncasecmp(uri, "xmpp:", 5) != 0) {
3547+
return FALSE;
3548+
}
3549+
3550+
const gchar* body = uri + 5;
3551+
const gchar* query = strchr(body, '?');
3552+
3553+
if (query == NULL) {
3554+
*out_room = g_uri_unescape_string(body, NULL);
3555+
*out_password = NULL;
3556+
return TRUE;
3557+
}
3558+
3559+
gchar* room_escaped = g_strndup(body, query - body);
3560+
*out_room = g_uri_unescape_string(room_escaped, NULL);
3561+
g_free(room_escaped);
3562+
3563+
const gchar* query_str = query + 1;
3564+
auto_gcharv gchar** parts = g_strsplit(query_str, ";", -1);
3565+
3566+
if (parts[0] == NULL || g_strcmp0(parts[0], "join") != 0) {
3567+
g_free(*out_room);
3568+
*out_room = NULL;
3569+
return FALSE;
3570+
}
3571+
3572+
gchar* password = NULL;
3573+
for (int i = 1; parts[i] != NULL; i++) {
3574+
gchar* eq = strchr(parts[i], '=');
3575+
if (eq != NULL) {
3576+
gchar* key = g_strndup(parts[i], eq - parts[i]);
3577+
if (g_strcmp0(key, "password") == 0) {
3578+
password = g_uri_unescape_string(eq + 1, NULL);
3579+
}
3580+
g_free(key);
3581+
}
3582+
}
3583+
3584+
*out_password = password;
3585+
return TRUE;
3586+
}
3587+
35433588
gboolean
35443589
cmd_join(ProfWin* window, const char* const command, gchar** args)
35453590
{
@@ -3566,7 +3611,19 @@ cmd_join(ProfWin* window, const char* const command, gchar** args)
35663611
return TRUE;
35673612
}
35683613

3569-
auto_jid Jid* room_arg = jid_create(args[0]);
3614+
auto_gchar gchar* room_jid = NULL;
3615+
auto_gchar gchar* uri_password = NULL;
3616+
3617+
if (g_ascii_strncasecmp(args[0], "xmpp:", 5) == 0) {
3618+
if (!_xmpp_uri_parse_join(args[0], &room_jid, &uri_password)) {
3619+
cons_show_error("Unsupported or invalid XMPP URI query type. Only 'join' is supported.");
3620+
return TRUE;
3621+
}
3622+
} else {
3623+
room_jid = g_strdup(args[0]);
3624+
}
3625+
3626+
auto_jid Jid* room_arg = jid_create(room_jid);
35703627
if (room_arg == NULL) {
35713628
cons_show_error("Specified room has incorrect format.");
35723629
cons_show("");
@@ -3580,11 +3637,11 @@ cmd_join(ProfWin* window, const char* const command, gchar** args)
35803637

35813638
// full room jid supplied (room@server)
35823639
if (room_arg->localpart) {
3583-
room = g_strdup(args[0]);
3640+
room = g_strdup(room_jid);
35843641

35853642
// server not supplied (room), use account preference
35863643
} else if (account->muc_service) {
3587-
room = g_strdup_printf("%s@%s", args[0], account->muc_service);
3644+
room = g_strdup_printf("%s@%s", room_jid, account->muc_service);
35883645

35893646
// no account preference
35903647
} else {
@@ -3613,6 +3670,10 @@ cmd_join(ProfWin* window, const char* const command, gchar** args)
36133670
nick = account->muc_nick;
36143671
}
36153672

3673+
if (!passwd) {
3674+
passwd = uri_password;
3675+
}
3676+
36163677
// When no password, check for invite with password
36173678
if (!passwd) {
36183679
passwd = muc_invite_password(room);

tests/unittests/command/test_cmd_join.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,68 @@ cmd_join__tests__uses_password_when_supplied(void** state)
158158
gboolean result = cmd_join(NULL, CMD_JOIN, args);
159159
assert_true(result);
160160
}
161+
162+
void
163+
cmd_join__tests__xmpp_uri_join(void** state)
164+
{
165+
gchar* account_name = g_strdup("an_account");
166+
char* room_uri = "xmpp:room@conf.server.org?join";
167+
char* expected_room = "room@conf.server.org";
168+
gchar* account_nick = g_strdup("a_nick");
169+
gchar* args[] = { room_uri, NULL };
170+
ProfAccount* account = account_new(account_name, g_strdup("user@server.org"), NULL, NULL,
171+
TRUE, NULL, 0, g_strdup("laptop"), NULL, NULL, 0, 0, 0, 0, 0, NULL, account_nick, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0);
172+
173+
will_return(connection_get_status, JABBER_CONNECTED);
174+
will_return(session_get_account_name, account_name);
175+
176+
expect_string(accounts_get_account, name, account_name);
177+
will_return(accounts_get_account, account);
178+
179+
expect_string(presence_join_room, room, expected_room);
180+
expect_string(presence_join_room, nick, account_nick);
181+
expect_value(presence_join_room, passwd, NULL);
182+
183+
gboolean result = cmd_join(NULL, CMD_JOIN, args);
184+
assert_true(result);
185+
}
186+
187+
void
188+
cmd_join__tests__xmpp_uri_join_with_password(void** state)
189+
{
190+
gchar* account_name = g_strdup("an_account");
191+
char* room_uri = "xmpp:room@conf.server.org?join;password=secret";
192+
char* expected_room = "room@conf.server.org";
193+
char* expected_password = "secret";
194+
gchar* account_nick = g_strdup("a_nick");
195+
gchar* args[] = { room_uri, NULL };
196+
ProfAccount* account = account_new(account_name, g_strdup("user@server.org"), NULL, NULL,
197+
TRUE, NULL, 0, g_strdup("laptop"), NULL, NULL, 0, 0, 0, 0, 0, NULL, account_nick, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0);
198+
199+
will_return(connection_get_status, JABBER_CONNECTED);
200+
will_return(session_get_account_name, account_name);
201+
202+
expect_string(accounts_get_account, name, account_name);
203+
will_return(accounts_get_account, account);
204+
205+
expect_string(presence_join_room, room, expected_room);
206+
expect_string(presence_join_room, nick, account_nick);
207+
expect_string(presence_join_room, passwd, expected_password);
208+
209+
gboolean result = cmd_join(NULL, CMD_JOIN, args);
210+
assert_true(result);
211+
}
212+
213+
void
214+
cmd_join__tests__xmpp_uri_invalid_query_type(void** state)
215+
{
216+
char* room_uri = "xmpp:room@conf.server.org?message";
217+
gchar* args[] = { room_uri, NULL };
218+
219+
will_return(connection_get_status, JABBER_CONNECTED);
220+
221+
expect_cons_show_error("Unsupported or invalid XMPP URI query type. Only 'join' is supported.");
222+
223+
gboolean result = cmd_join(NULL, CMD_JOIN, args);
224+
assert_true(result);
225+
}

tests/unittests/command/test_cmd_join.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,8 @@ void cmd_join__tests__uses_account_mucservice_when_no_service_specified(void** s
1010
void cmd_join__tests__uses_supplied_nick(void** state);
1111
void cmd_join__tests__uses_account_nick_when_not_supplied(void** state);
1212
void cmd_join__tests__uses_password_when_supplied(void** state);
13+
void cmd_join__tests__xmpp_uri_join(void** state);
14+
void cmd_join__tests__xmpp_uri_join_with_password(void** state);
15+
void cmd_join__tests__xmpp_uri_invalid_query_type(void** state);
1316

1417
#endif

tests/unittests/unittests.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,9 @@ main(int argc, char* argv[])
642642
muc_unit_test(cmd_join__tests__uses_supplied_nick),
643643
muc_unit_test(cmd_join__tests__uses_account_nick_when_not_supplied),
644644
muc_unit_test(cmd_join__tests__uses_password_when_supplied),
645+
muc_unit_test(cmd_join__tests__xmpp_uri_join),
646+
muc_unit_test(cmd_join__tests__xmpp_uri_join_with_password),
647+
cmocka_unit_test(cmd_join__tests__xmpp_uri_invalid_query_type),
645648

646649
cmocka_unit_test(cmd_roster__shows__message_when_disconnecting),
647650
cmocka_unit_test(cmd_roster__shows__message_when_connecting),

0 commit comments

Comments
 (0)