+static int match_user(xmpp_user_t *usr, const char *ptrn)
+{
+ char tmp[32];
+
+ const char *user = usr->dest;
+ const char *full = usr->full_name;
+ const char *nick = usr->mention_name;
+
+ /* Match all users */
+ if (!ptrn || !ptrn[0])
+ return 1;
+
+ /* Match user id and mention name */
+ if (user && strcasestr(user, ptrn) == user)
+ return 1;
+ if (nick && strcasestr(nick, ptrn) == nick)
+ return 1;
+
+ /* Full name matching */
+ if (!full || !full[0])
+ return 0;
+
+ /* Match first name */
+ if (strcasestr(full, ptrn) == full)
+ return 1;
+
+ /* Match last name */
+ snprintf(tmp, sizeof(tmp), " %s", ptrn);
+ if (strcasestr(full, tmp))
+ return 1;
+ snprintf(tmp, sizeof(tmp), "-%s", ptrn);
+ if (strcasestr(full, tmp))
+ return 1;
+
+ /* Match first initial last name */
+ if (tolower(full[0]) == tolower(ptrn[0])) {
+ snprintf(tmp, sizeof(tmp), " %s", &ptrn[1]);
+ if (strcasestr(full, tmp))
+ return 1;
+ snprintf(tmp, sizeof(tmp), "-%s", &ptrn[1]);
+ if (strcasestr(full, tmp))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int match_channel(xmpp_channel_t *chan, const char *ptrn)
+{
+ const char *dest = chan->dest;
+ const char *room = chan->room;
+
+ /* Match all users */
+ if (!ptrn || !ptrn[0])
+ return 1;
+
+ /* Match dest and channel name */
+ if (dest && strcasestr(dest, ptrn))
+ return 1;
+ if (room && strcasestr(room, ptrn))
+ return 1;
+
+ return 0;
+}
+
+static void complete_xmpp_user(xmpp_server_t *srv, const char *prefix, int mention)
+{
+ for (user_t *cur = users; cur; cur = cur->next) {
+ if (cur->server != &srv->server)
+ continue;
+ xmpp_user_t *usr = (xmpp_user_t *)cur;
+ if (usr->muc)
+ continue;
+ if (match_user(usr, prefix)) {
+ if (!mention)
+ complete_item(prefix, usr->dest, usr->full_name);
+ else if (usr->mention_name)
+ complete_item(prefix, usr->mention_name, usr->full_name);
+ else
+ complete_item(prefix, usr->full_name, "");
+ }
+ }
+}
+
+static void complete_xmpp_channel(xmpp_server_t *srv, const char *prefix)
+{
+ for (channel_t *cur = channels; cur; cur = cur->next) {
+ if (cur->server != &srv->server)
+ continue;
+ xmpp_channel_t *chan = (xmpp_channel_t *)cur;
+ if (!chan->muc)
+ continue;
+ if (match_channel(chan, prefix))
+ complete_item(prefix, chan->dest, chan->name ?: chan->room);
+ }
+}
+