unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

user.c (16988B)

      1 /* user.* RPC calls
      2  * (C) Copyright 2022-.. Bram Matthys (Syzop) and the UnrealIRCd team
      3  * License: GPLv2 or later
      4  */
      5 
      6 #include "unrealircd.h"
      7 
      8 ModuleHeader MOD_HEADER
      9 = {
     10 	"rpc/user",
     11 	"1.0.7",
     12 	"user.* RPC calls",
     13 	"UnrealIRCd Team",
     14 	"unrealircd-6",
     15 };
     16 
     17 /* Forward declarations */
     18 RPC_CALL_FUNC(rpc_user_list);
     19 RPC_CALL_FUNC(rpc_user_get);
     20 RPC_CALL_FUNC(rpc_user_set_nick);
     21 RPC_CALL_FUNC(rpc_user_set_username);
     22 RPC_CALL_FUNC(rpc_user_set_realname);
     23 RPC_CALL_FUNC(rpc_user_set_vhost);
     24 RPC_CALL_FUNC(rpc_user_set_mode);
     25 RPC_CALL_FUNC(rpc_user_set_snomask);
     26 RPC_CALL_FUNC(rpc_user_set_oper);
     27 RPC_CALL_FUNC(rpc_user_kill);
     28 RPC_CALL_FUNC(rpc_user_quit);
     29 RPC_CALL_FUNC(rpc_user_join);
     30 RPC_CALL_FUNC(rpc_user_part);
     31 
     32 MOD_INIT()
     33 {
     34 	RPCHandlerInfo r;
     35 
     36 	MARK_AS_OFFICIAL_MODULE(modinfo);
     37 
     38 	memset(&r, 0, sizeof(r));
     39 	r.method = "user.list";
     40 	r.loglevel = ULOG_DEBUG;
     41 	r.call = rpc_user_list;
     42 	if (!RPCHandlerAdd(modinfo->handle, &r))
     43 	{
     44 		config_error("[rpc/user] Could not register RPC handler");
     45 		return MOD_FAILED;
     46 	}
     47 	memset(&r, 0, sizeof(r));
     48 	r.method = "user.get";
     49 	r.loglevel = ULOG_DEBUG;
     50 	r.call = rpc_user_get;
     51 	if (!RPCHandlerAdd(modinfo->handle, &r))
     52 	{
     53 		config_error("[rpc/user] Could not register RPC handler");
     54 		return MOD_FAILED;
     55 	}
     56 	memset(&r, 0, sizeof(r));
     57 	r.method = "user.set_nick";
     58 	r.call = rpc_user_set_nick;
     59 	if (!RPCHandlerAdd(modinfo->handle, &r))
     60 	{
     61 		config_error("[rpc/user] Could not register RPC handler");
     62 		return MOD_FAILED;
     63 	}
     64 	memset(&r, 0, sizeof(r));
     65 	r.method = "user.set_username";
     66 	r.call = rpc_user_set_username;
     67 	if (!RPCHandlerAdd(modinfo->handle, &r))
     68 	{
     69 		config_error("[rpc/user] Could not register RPC handler");
     70 		return MOD_FAILED;
     71 	}
     72 	memset(&r, 0, sizeof(r));
     73 	r.method = "user.set_realname";
     74 	r.call = rpc_user_set_realname;
     75 	if (!RPCHandlerAdd(modinfo->handle, &r))
     76 	{
     77 		config_error("[rpc/user] Could not register RPC handler");
     78 		return MOD_FAILED;
     79 	}
     80 	memset(&r, 0, sizeof(r));
     81 	r.method = "user.set_vhost";
     82 	r.call = rpc_user_set_vhost;
     83 	if (!RPCHandlerAdd(modinfo->handle, &r))
     84 	{
     85 		config_error("[rpc/user] Could not register RPC handler");
     86 		return MOD_FAILED;
     87 	}
     88 	memset(&r, 0, sizeof(r));
     89 	r.method = "user.set_mode";
     90 	r.call = rpc_user_set_mode;
     91 	if (!RPCHandlerAdd(modinfo->handle, &r))
     92 	{
     93 		config_error("[rpc/user] Could not register RPC handler");
     94 		return MOD_FAILED;
     95 	}
     96 	memset(&r, 0, sizeof(r));
     97 	r.method = "user.set_snomask";
     98 	r.call = rpc_user_set_snomask;
     99 	if (!RPCHandlerAdd(modinfo->handle, &r))
    100 	{
    101 		config_error("[rpc/user] Could not register RPC handler");
    102 		return MOD_FAILED;
    103 	}
    104 	memset(&r, 0, sizeof(r));
    105 	r.method = "user.set_oper";
    106 	r.call = rpc_user_set_oper;
    107 	if (!RPCHandlerAdd(modinfo->handle, &r))
    108 	{
    109 		config_error("[rpc/user] Could not register RPC handler");
    110 		return MOD_FAILED;
    111 	}
    112 	memset(&r, 0, sizeof(r));
    113 	r.method = "user.kill";
    114 	r.call = rpc_user_kill;
    115 	if (!RPCHandlerAdd(modinfo->handle, &r))
    116 	{
    117 		config_error("[rpc/user] Could not register RPC handler");
    118 		return MOD_FAILED;
    119 	}
    120 	memset(&r, 0, sizeof(r));
    121 	r.method = "user.quit";
    122 	r.call = rpc_user_quit;
    123 	if (!RPCHandlerAdd(modinfo->handle, &r))
    124 	{
    125 		config_error("[rpc/user] Could not register RPC handler");
    126 		return MOD_FAILED;
    127 	}
    128 	memset(&r, 0, sizeof(r));
    129 	r.method = "user.join";
    130 	r.call = rpc_user_join;
    131 	if (!RPCHandlerAdd(modinfo->handle, &r))
    132 	{
    133 		config_error("[rpc/user] Could not register RPC handler");
    134 		return MOD_FAILED;
    135 	}
    136 	memset(&r, 0, sizeof(r));
    137 	r.method = "user.part";
    138 	r.call = rpc_user_part;
    139 	if (!RPCHandlerAdd(modinfo->handle, &r))
    140 	{
    141 		config_error("[rpc/user] Could not register RPC handler");
    142 		return MOD_FAILED;
    143 	}
    144 
    145 	return MOD_SUCCESS;
    146 }
    147 
    148 MOD_LOAD()
    149 {
    150 	return MOD_SUCCESS;
    151 }
    152 
    153 MOD_UNLOAD()
    154 {
    155 	return MOD_SUCCESS;
    156 }
    157 
    158 RPC_CALL_FUNC(rpc_user_list)
    159 {
    160 	json_t *result, *list, *item;
    161 	Client *acptr;
    162 	int details;
    163 
    164 	OPTIONAL_PARAM_INTEGER("object_detail_level", details, 2);
    165 	if (details == 3)
    166 	{
    167 		rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Using an 'object_detail_level' of 3 is not allowed in user.* calls, use 0, 1, 2 or 4.");
    168 		return;
    169 	}
    170 
    171 	result = json_object();
    172 	list = json_array();
    173 	json_object_set_new(result, "list", list);
    174 
    175 	list_for_each_entry(acptr, &client_list, client_node)
    176 	{
    177 		if (!IsUser(acptr))
    178 			continue;
    179 
    180 		item = json_object();
    181 		json_expand_client(item, NULL, acptr, details);
    182 		json_array_append_new(list, item);
    183 	}
    184 
    185 	rpc_response(client, request, result);
    186 	json_decref(result);
    187 }
    188 
    189 RPC_CALL_FUNC(rpc_user_get)
    190 {
    191 	json_t *result, *list, *item;
    192 	const char *nick;
    193 	Client *acptr;
    194 	int details;
    195 
    196 	REQUIRE_PARAM_STRING("nick", nick);
    197 
    198 	OPTIONAL_PARAM_INTEGER("object_detail_level", details, 4);
    199 	if (details == 3)
    200 	{
    201 		rpc_error(client, request, JSON_RPC_ERROR_INVALID_PARAMS, "Using an 'object_detail_level' of 3 is not allowed in user.* calls, use 0, 1, 2 or 4.");
    202 		return;
    203 	}
    204 
    205 	if (!(acptr = find_user(nick, NULL)))
    206 	{
    207 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found");
    208 		return;
    209 	}
    210 
    211 	result = json_object();
    212 	json_expand_client(result, "client", acptr, details);
    213 	rpc_response(client, request, result);
    214 	json_decref(result);
    215 }
    216 
    217 RPC_CALL_FUNC(rpc_user_set_nick)
    218 {
    219 	json_t *result, *list, *item;
    220 	MessageTag *mtags = NULL;
    221 	const char *args[5];
    222 	const char *nick, *newnick_requested, *str;
    223 	int force = 0;
    224 	char newnick[NICKLEN+1];
    225 	char tsbuf[32];
    226 	Client *acptr;
    227 
    228 	REQUIRE_PARAM_STRING("nick", nick);
    229 	REQUIRE_PARAM_STRING("newnick", newnick_requested);
    230 	strlcpy(newnick, newnick_requested, iConf.nick_length + 1);
    231 	OPTIONAL_PARAM_BOOLEAN("force", force, 0);
    232 
    233 	if (!(acptr = find_user(nick, NULL)))
    234 	{
    235 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found");
    236 		return;
    237 	}
    238 
    239 	if (!do_nick_name(newnick) || strcmp(newnick, newnick_requested) ||
    240 	    !strcasecmp(newnick, "IRC") || !strcasecmp(newnick, "IRCd"))
    241 	{
    242 		rpc_error(client, request, JSON_RPC_ERROR_INVALID_NAME, "New nickname contains forbidden character(s) or is too long");
    243 		return;
    244 	}
    245 
    246 	if (!strcmp(nick, newnick))
    247 	{
    248 		rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "Old nickname and new nickname are identical");
    249 		return;
    250 	}
    251 
    252 	if (!force)
    253 	{
    254 		/* Check other restrictions */
    255 		Client *check = find_user(newnick, NULL);
    256 		int ishold = 0;
    257 
    258 		/* Check if in use by someone else (do allow case-changing) */
    259 		if (check && (acptr != check))
    260 		{
    261 			rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "New nickname is already taken by another user");
    262 			return;
    263 		}
    264 
    265 		// Can't really check for spamfilter here, since it assumes user is local
    266 
    267 		// But we can check q-lines...
    268 		if (find_qline(acptr, newnick, &ishold))
    269 		{
    270 			rpc_error(client, request, JSON_RPC_ERROR_INVALID_NAME, "New nickname is forbidden by q-line");
    271 			return;
    272 		}
    273 	}
    274 
    275 	args[0] = NULL;
    276 	args[1] = acptr->name;
    277 	args[2] = newnick;
    278 	snprintf(tsbuf, sizeof(tsbuf), "%lld", (long long)TStime());
    279 	args[3] = tsbuf;
    280 	args[4] = NULL;
    281 	mtag_add_issued_by(&mtags, client, NULL);
    282 	do_cmd(&me, mtags, "SVSNICK", 4, args);
    283 	safe_free_message_tags(mtags);
    284 
    285 	/* Simply return success */
    286 	result = json_boolean(1);
    287 	rpc_response(client, request, result);
    288 	json_decref(result);
    289 }
    290 
    291 RPC_CALL_FUNC(rpc_user_set_username)
    292 {
    293 	json_t *result, *list, *item;
    294 	const char *args[4];
    295 	const char *nick, *username, *str;
    296 	MessageTag *mtags = NULL;
    297 	Client *acptr;
    298 
    299 	REQUIRE_PARAM_STRING("nick", nick);
    300 	REQUIRE_PARAM_STRING("username", username);
    301 
    302 	if (!(acptr = find_user(nick, NULL)))
    303 	{
    304 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found");
    305 		return;
    306 	}
    307 
    308 	if (!valid_username(username))
    309 	{
    310 		rpc_error(client, request, JSON_RPC_ERROR_INVALID_NAME, "New username contains forbidden character(s) or is too long");
    311 		return;
    312 	}
    313 
    314 	if (!strcmp(acptr->user->username, username))
    315 	{
    316 		rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "Old and new user name are identical");
    317 		return;
    318 	}
    319 
    320 	args[0] = NULL;
    321 	args[1] = acptr->name;
    322 	args[2] = username;
    323 	args[3] = NULL;
    324 	mtag_add_issued_by(&mtags, client, NULL);
    325 	do_cmd(&me, mtags, "CHGIDENT", 3, args);
    326 	safe_free_message_tags(mtags);
    327 
    328 	/* Return result */
    329 	if (!strcmp(acptr->user->username, username))
    330 		result = json_boolean(1);
    331 	else
    332 		result = json_boolean(0);
    333 	rpc_response(client, request, result);
    334 	json_decref(result);
    335 }
    336 
    337 RPC_CALL_FUNC(rpc_user_set_realname)
    338 {
    339 	json_t *result, *list, *item;
    340 	const char *args[4];
    341 	const char *nick, *realname, *str;
    342 	MessageTag *mtags = NULL;
    343 	Client *acptr;
    344 
    345 	REQUIRE_PARAM_STRING("nick", nick);
    346 	REQUIRE_PARAM_STRING("realname", realname);
    347 
    348 	if (!(acptr = find_user(nick, NULL)))
    349 	{
    350 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found");
    351 		return;
    352 	}
    353 
    354 	if (strlen(realname) > REALLEN)
    355 	{
    356 		rpc_error(client, request, JSON_RPC_ERROR_INVALID_NAME, "New real name is too long");
    357 		return;
    358 	}
    359 
    360 	if (!strcmp(acptr->info, realname))
    361 	{
    362 		rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "Old and new real name are identical");
    363 		return;
    364 	}
    365 
    366 	args[0] = NULL;
    367 	args[1] = acptr->name;
    368 	args[2] = realname;
    369 	args[3] = NULL;
    370 	mtag_add_issued_by(&mtags, client, NULL);
    371 	do_cmd(&me, mtags, "CHGNAME", 3, args);
    372 	safe_free_message_tags(mtags);
    373 
    374 	/* Return result */
    375 	if (!strcmp(acptr->info, realname))
    376 		result = json_boolean(1);
    377 	else
    378 		result = json_boolean(0);
    379 	rpc_response(client, request, result);
    380 	json_decref(result);
    381 }
    382 
    383 RPC_CALL_FUNC(rpc_user_set_vhost)
    384 {
    385 	json_t *result, *list, *item;
    386 	const char *args[4];
    387 	const char *nick, *vhost, *str;
    388 	MessageTag *mtags = NULL;
    389 	Client *acptr;
    390 
    391 	REQUIRE_PARAM_STRING("nick", nick);
    392 	REQUIRE_PARAM_STRING("vhost", vhost);
    393 
    394 	if (!(acptr = find_user(nick, NULL)))
    395 	{
    396 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found");
    397 		return;
    398 	}
    399 
    400 	if ((strlen(vhost) > HOSTLEN) || !valid_host(vhost, 0))
    401 	{
    402 		rpc_error(client, request, JSON_RPC_ERROR_INVALID_NAME, "New vhost contains forbidden character(s) or is too long");
    403 		return;
    404 	}
    405 
    406 	if (!strcmp(GetHost(acptr), vhost))
    407 	{
    408 		rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "Old and new vhost are identical");
    409 		return;
    410 	}
    411 
    412 	args[0] = NULL;
    413 	args[1] = acptr->name;
    414 	args[2] = vhost;
    415 	args[3] = NULL;
    416 	mtag_add_issued_by(&mtags, client, NULL);
    417 	do_cmd(&me, mtags, "CHGHOST", 3, args);
    418 	safe_free_message_tags(mtags);
    419 
    420 	/* Return result */
    421 	if (!strcmp(GetHost(acptr), vhost))
    422 		result = json_boolean(1);
    423 	else
    424 		result = json_boolean(0);
    425 	rpc_response(client, request, result);
    426 	json_decref(result);
    427 }
    428 
    429 RPC_CALL_FUNC(rpc_user_set_mode)
    430 {
    431 	json_t *result, *list, *item;
    432 	const char *args[4];
    433 	const char *nick, *modes, *str;
    434 	int hidden;
    435 	MessageTag *mtags = NULL;
    436 	Client *acptr;
    437 
    438 	REQUIRE_PARAM_STRING("nick", nick);
    439 	REQUIRE_PARAM_STRING("modes", modes);
    440 	OPTIONAL_PARAM_BOOLEAN("hidden", hidden, 0);
    441 
    442 	if (!(acptr = find_user(nick, NULL)))
    443 	{
    444 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found");
    445 		return;
    446 	}
    447 
    448 	args[0] = NULL;
    449 	args[1] = acptr->name;
    450 	args[2] = modes;
    451 	args[3] = NULL;
    452 	mtag_add_issued_by(&mtags, client, NULL);
    453 	do_cmd(&me, mtags, hidden ? "SVSMODE" : "SVS2MODE", 3, args);
    454 	safe_free_message_tags(mtags);
    455 
    456 	/* Return result (always true) */
    457 	result = json_boolean(1);
    458 	rpc_response(client, request, result);
    459 	json_decref(result);
    460 }
    461 
    462 RPC_CALL_FUNC(rpc_user_set_snomask)
    463 {
    464 	json_t *result, *list, *item;
    465 	const char *args[4];
    466 	const char *nick, *snomask, *str;
    467 	int hidden;
    468 	MessageTag *mtags = NULL;
    469 	Client *acptr;
    470 
    471 	REQUIRE_PARAM_STRING("nick", nick);
    472 	REQUIRE_PARAM_STRING("snomask", snomask);
    473 	OPTIONAL_PARAM_BOOLEAN("hidden", hidden, 0);
    474 
    475 	if (!(acptr = find_user(nick, NULL)))
    476 	{
    477 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found");
    478 		return;
    479 	}
    480 
    481 	args[0] = NULL;
    482 	args[1] = acptr->name;
    483 	args[2] = snomask;
    484 	args[3] = NULL;
    485 	mtag_add_issued_by(&mtags, client, NULL);
    486 	do_cmd(&me, mtags, hidden ? "SVSSNO" : "SVS2SNO", 3, args);
    487 	safe_free_message_tags(mtags);
    488 
    489 	/* Return result (always true) */
    490 	result = json_boolean(1);
    491 	rpc_response(client, request, result);
    492 	json_decref(result);
    493 }
    494 
    495 RPC_CALL_FUNC(rpc_user_set_oper)
    496 {
    497 	json_t *result, *list, *item;
    498 	const char *args[9];
    499 	const char *nick, *oper_account, *oper_class;
    500 	const char *class=NULL, *modes=NULL, *snomask=NULL, *vhost=NULL;
    501 	MessageTag *mtags = NULL;
    502 	Client *acptr;
    503 	char default_modes[64];
    504 
    505 	REQUIRE_PARAM_STRING("nick", nick);
    506 	REQUIRE_PARAM_STRING("oper_account", oper_account);
    507 	REQUIRE_PARAM_STRING("oper_class", oper_class);
    508 	OPTIONAL_PARAM_STRING("class", class);
    509 	OPTIONAL_PARAM_STRING("modes", modes);
    510 	OPTIONAL_PARAM_STRING("snomask", snomask);
    511 	OPTIONAL_PARAM_STRING("vhost", vhost);
    512 
    513 	if (!(acptr = find_user(nick, NULL)))
    514 	{
    515 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found");
    516 		return;
    517 	}
    518 
    519 	if (modes == NULL)
    520 	{
    521 		strlcpy(default_modes, get_usermode_string_raw(OPER_MODES), sizeof(default_modes));
    522 		modes = default_modes;
    523 	}
    524 
    525 	args[0] = NULL;
    526 	args[1] = acptr->name;
    527 	args[2] = oper_account;
    528 	args[3] = oper_class;
    529 	args[4] = class ? class : "opers";
    530 	args[5] = modes;
    531 	args[6] = snomask ? snomask : iConf.oper_snomask;
    532 	args[7] = vhost ? vhost : "-";
    533 	args[8] = NULL;
    534 	mtag_add_issued_by(&mtags, client, NULL);
    535 	do_cmd(&me, mtags, "SVSO", 8, args);
    536 	safe_free_message_tags(mtags);
    537 
    538 	/* Return result (always true) */
    539 	result = json_boolean(1);
    540 	rpc_response(client, request, result);
    541 	json_decref(result);
    542 }
    543 
    544 RPC_CALL_FUNC(rpc_user_kill)
    545 {
    546 	json_t *result, *list, *item;
    547 	const char *args[4];
    548 	const char *nick, *reason;
    549 	MessageTag *mtags = NULL;
    550 	Client *acptr;
    551 
    552 	REQUIRE_PARAM_STRING("nick", nick);
    553 	REQUIRE_PARAM_STRING("reason", reason);
    554 
    555 	if (!(acptr = find_user(nick, NULL)))
    556 	{
    557 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found");
    558 		return;
    559 	}
    560 
    561 	args[0] = NULL;
    562 	args[1] = acptr->name;
    563 	args[2] = reason;
    564 	args[3] = NULL;
    565 	mtag_add_issued_by(&mtags, client, NULL);
    566 	do_cmd(&me, mtags, "KILL", 3, args);
    567 	safe_free_message_tags(mtags);
    568 
    569 	/* Return result */
    570 	if ((acptr = find_user(nick, NULL)) && !IsDead(acptr))
    571 		result = json_boolean(0);
    572 	else
    573 		result = json_boolean(1);
    574 	rpc_response(client, request, result);
    575 	json_decref(result);
    576 }
    577 
    578 RPC_CALL_FUNC(rpc_user_quit)
    579 {
    580 	json_t *result, *list, *item;
    581 	const char *args[4];
    582 	const char *nick, *reason;
    583 	MessageTag *mtags = NULL;
    584 	Client *acptr;
    585 
    586 	REQUIRE_PARAM_STRING("nick", nick);
    587 	REQUIRE_PARAM_STRING("reason", reason);
    588 
    589 	if (!(acptr = find_user(nick, NULL)))
    590 	{
    591 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found");
    592 		return;
    593 	}
    594 
    595 	args[0] = NULL;
    596 	args[1] = acptr->name;
    597 	args[2] = reason;
    598 	args[3] = NULL;
    599 	mtag_add_issued_by(&mtags, client, NULL);
    600 	do_cmd(&me, mtags, "SVSKILL", 3, args);
    601 	safe_free_message_tags(mtags);
    602 
    603 	/* Return result */
    604 	if ((acptr = find_user(nick, NULL)) && !IsDead(acptr))
    605 		result = json_boolean(0);
    606 	else
    607 		result = json_boolean(1);
    608 	rpc_response(client, request, result);
    609 	json_decref(result);
    610 }
    611 
    612 RPC_CALL_FUNC(rpc_user_join)
    613 {
    614 	json_t *result, *list, *item;
    615 	const char *args[5];
    616 	const char *nick, *channel, *key=NULL;
    617 	Client *acptr;
    618 	MessageTag *mtags = NULL;
    619 	int force = 0;
    620 
    621 	REQUIRE_PARAM_STRING("nick", nick);
    622 	REQUIRE_PARAM_STRING("channel", channel);
    623 	OPTIONAL_PARAM_STRING("key", key);
    624 	OPTIONAL_PARAM_BOOLEAN("force", force, 0);
    625 
    626 	if (!(acptr = find_user(nick, NULL)))
    627 	{
    628 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found");
    629 		return;
    630 	}
    631 
    632 	mtag_add_issued_by(&mtags, client, NULL);
    633 
    634 	args[0] = NULL;
    635 	args[1] = acptr->name;
    636 	args[2] = channel;
    637 
    638 	if (force == 0)
    639 	{
    640 		args[3] = key;
    641 		args[4] = NULL;
    642 		do_cmd(&me, mtags, "SVSJOIN", key ? 4 : 3, args);
    643 	} else {
    644 		args[3] = NULL;
    645 		do_cmd(&me, mtags, "SAJOIN", 3, args);
    646 	}
    647 
    648 	safe_free_message_tags(mtags);
    649 
    650 	/* Return result -- yeah this is always true, not so good.. :D
    651 	 * It is that way because we (this server) may not actually
    652 	 * do the SVSJOIN at all, we may be just relaying it to some
    653 	 * other server.
    654 	 */
    655 	result = json_boolean(1);
    656 	rpc_response(client, request, result);
    657 	json_decref(result);
    658 }
    659 
    660 RPC_CALL_FUNC(rpc_user_part)
    661 {
    662 	json_t *result, *list, *item;
    663 	const char *args[5];
    664 	const char *nick, *channel, *reason=NULL;
    665 	Client *acptr;
    666 	MessageTag *mtags = NULL;
    667 	int force = 0;
    668 
    669 	REQUIRE_PARAM_STRING("nick", nick);
    670 	REQUIRE_PARAM_STRING("channel", channel);
    671 	OPTIONAL_PARAM_STRING("reason", reason);
    672 	OPTIONAL_PARAM_BOOLEAN("force", force, 0);
    673 
    674 	if (!(acptr = find_user(nick, NULL)))
    675 	{
    676 		rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Nickname not found");
    677 		return;
    678 	}
    679 
    680 	args[0] = NULL;
    681 	args[1] = acptr->name;
    682 	args[2] = channel;
    683 	args[3] = reason;
    684 	args[4] = NULL;
    685 	mtag_add_issued_by(&mtags, client, NULL);
    686 	do_cmd(&me, NULL, force ? "SAPART" : "SVSPART", reason ? 4 : 3, args);
    687 	safe_free_message_tags(mtags);
    688 
    689 	/* Return result. Always 'true' at the moment.
    690 	 * Technically we could check if the user is in all of these channels.
    691 	 * But then again, do we really want to return failure if one specified
    692 	 * channel does not exist out of X channels to be parted? Not worth it.
    693 	 */
    694 	result = json_boolean(1);
    695 	rpc_response(client, request, result);
    696 	json_decref(result);
    697 }