Пример #1
0
//  muc_get_item_info(...)
// Get room member's information from xmlndata.
// The variables must be initialized before calling this function,
// because they are not touched if the relevant information is missing.
// Note that *actor should be freed by the caller.
static void muc_get_item_info(const char *from, LmMessageNode *xmldata,
                              enum imrole *mbrole, enum imaffiliation *mbaffil,
                              const char **mbjid, const char **mbnick,
                              char **actor, const char **reason)
{
  LmMessageNode *y, *z;
  const char *p, *actorjid, *actornick;

  y = lm_message_node_find_child(xmldata, "item");
  if (!y)
    return;

  p = lm_message_node_get_attribute(y, "affiliation");
  if (p) {
    if (!strcmp(p, "owner"))        *mbaffil = affil_owner;
    else if (!strcmp(p, "admin"))   *mbaffil = affil_admin;
    else if (!strcmp(p, "member"))  *mbaffil = affil_member;
    else if (!strcmp(p, "outcast")) *mbaffil = affil_outcast;
    else if (!strcmp(p, "none"))    *mbaffil = affil_none;
    else scr_LogPrint(LPRINT_LOGNORM, "<%s>: Unknown affiliation \"%s\"",
                      from, p);
  }
  p = lm_message_node_get_attribute(y, "role");
  if (p) {
    if (!strcmp(p, "moderator"))        *mbrole = role_moderator;
    else if (!strcmp(p, "participant")) *mbrole = role_participant;
    else if (!strcmp(p, "visitor"))     *mbrole = role_visitor;
    else if (!strcmp(p, "none"))        *mbrole = role_none;
    else scr_LogPrint(LPRINT_LOGNORM, "<%s>: Unknown role \"%s\"",
                      from, p);
  }
  *mbjid = lm_message_node_get_attribute(y, "jid");
  *mbnick = lm_message_node_get_attribute(y, "nick");
  // For kick/ban, there can be actor and reason tags
  z = lm_message_node_find_child(y, "actor");
  if (z) {
    actornick = lm_message_node_get_attribute(z, "nick");
    actorjid  = lm_message_node_get_attribute(z, "jid");
    if (actorjid) {
      if (actornick) {
        // We have both the actor's jid and nick
        *actor = g_strdup_printf("%s <%s>", actornick, actorjid);
      } else {
        *actor = g_strdup(actorjid); // jid only
      }
    } else if (!actorjid && actornick) {
      // We only have the nickname
      *actor = g_strdup(actornick);
    }
  }

  *reason = lm_message_node_get_child_value(y, "reason");
  if (*reason && !**reason)
    *reason = NULL;
}
Пример #2
0
/*
 * Обработчик входящих сообщений
 */
LmHandlerResult handle_messages(LmMessageHandler *handler,
                  LmConnection *connect, LmMessage *m, gpointer data) {
  printf("\nОбрабатываю событие LM_MESSAGE_TYPE_MESSAGE\n");

  const gchar *from, *to, *body, *xmlns;
        gchar  *str, *sstr = NULL;
  
  LmMessageSubType mstype;

  xmlns = lm_message_node_get_child_attribute(m->node, "x", "xmlns");
  if(!xmlns)
    xmlns = "";
  if(!strstr(xmlns, "delay")) {

    from = lm_message_node_get_attribute(m->node, "from");
    to = lm_message_node_get_attribute(m->node, "to");
    body = lm_message_node_get_child_value(m->node, "body");

    mstype = lm_message_get_sub_type(m);

    if(body) {
      str = g_strdup(body);
      sstr = g_strdup(strtok(str, " "));
    }

    if(sstr) {

      printf("Incoming message\n\tfrom: %s\n\tto: %s\n\tbody: %s\n",
              from, to, body);

      handler_cmd(connect, sstr, strchr(body, ' '));
    }
    
    free(str);
    free(sstr);
  }
  
  usleep(100000);
  lm_message_unref(m);
  return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
Пример #3
0
static void storage_bookmarks_parse_conference(LmMessageNode *node)
{
  const char *fjid, *name, *autojoin;
  const char *pstatus, *awhois, *fjoins, *group;
  char *bjid;
  GSList *room_elt;

  fjid = lm_message_node_get_attribute(node, "jid");
  if (!fjid)
    return;
  name = lm_message_node_get_attribute(node, "name");
  autojoin = lm_message_node_get_attribute(node, "autojoin");
  awhois = lm_message_node_get_attribute(node, "autowhois");
  pstatus = lm_message_node_get_child_value(node, "print_status");
  fjoins = lm_message_node_get_child_value(node, "flag_joins");
  group = lm_message_node_get_child_value(node, "group");

  bjid = jidtodisp(fjid); // Bare jid

  // Make sure this is a room (it can be a conversion user->room)
  room_elt = roster_find(bjid, jidsearch, 0);
  if (!room_elt) {
    room_elt = roster_add_user(bjid, name, group, ROSTER_TYPE_ROOM,
                               sub_none, -1);
  } else {
    buddy_settype(room_elt->data, ROSTER_TYPE_ROOM);
    /*
    // If the name is available, should we use it?
    // I don't think so, it would be confusing because this item is already
    // in the roster.
    if (name)
      buddy_setname(room_elt->data, name);

    // The same question for roster group.
    if (group)
      buddy_setgroup(room_elt->data, group);
    */
  }

  // Set the print_status and auto_whois values
  if (pstatus) {
    enum room_printstatus i;
    for (i = status_none; i <= status_all; i++)
      if (!strcasecmp(pstatus, strprintstatus[i]))
        break;
    if (i <= status_all)
      buddy_setprintstatus(room_elt->data, i);
  }
  if (awhois) {
    enum room_autowhois i = autowhois_default;
    if (!g_strcmp0(awhois, "1") || !(g_strcmp0(awhois, "true")))
      i = autowhois_on;
    else if (!g_strcmp0(awhois, "0") || !(g_strcmp0(awhois, "false")))
      i = autowhois_off;
    if (i != autowhois_default)
      buddy_setautowhois(room_elt->data, i);
  }
  if (fjoins) {
    enum room_flagjoins i;
    for (i = flagjoins_none; i <= flagjoins_all; i++)
      if (!strcasecmp(fjoins, strflagjoins[i]))
        break;
    if (i <= flagjoins_all)
      buddy_setflagjoins(room_elt->data, i);
  }

  // Is autojoin set?
  // If it is, we'll look up for more information (nick? password?) and
  // try to join the room.
  if (autojoin && !g_strcmp0(autojoin, "1")) {
    const char *nick, *passwd;
    char *tmpnick = NULL;
    nick = lm_message_node_get_child_value(node, "nick");
    passwd = lm_message_node_get_child_value(node, "password");
    if (!nick || !*nick)
      nick = tmpnick = default_muc_nickname(NULL);
    // Let's join now
    scr_LogPrint(LPRINT_LOGNORM, "Auto-join bookmark <%s>", bjid);
    xmpp_room_join(bjid, nick, passwd);
    g_free(tmpnick);
  }
  g_free(bjid);

  buddylist_build();
  update_roster = TRUE;
}
Пример #4
0
static void handle_vcard_node(const char *barejid, LmMessageNode *vcardnode)
{
  LmMessageNode *x;
  const char *p;

  for (x = vcardnode->children ; x; x = x->next) {
    const char *data;
    enum vcard_attr vcard_attrib = 0;

    p = x->name;
    if (!p)
      continue;

    data = lm_message_node_get_value(x);

    if (!g_strcmp0(p, "FN"))
      display_vcard_item(barejid, "Name", vcard_attrib, data);
    else if (!g_strcmp0(p, "NICKNAME"))
      display_vcard_item(barejid, "Nickname", vcard_attrib, data);
    else if (!g_strcmp0(p, "URL"))
      display_vcard_item(barejid, "URL", vcard_attrib, data);
    else if (!g_strcmp0(p, "BDAY"))
      display_vcard_item(barejid, "Birthday", vcard_attrib, data);
    else if (!g_strcmp0(p, "TZ"))
      display_vcard_item(barejid, "Timezone", vcard_attrib, data);
    else if (!g_strcmp0(p, "TITLE"))
      display_vcard_item(barejid, "Title", vcard_attrib, data);
    else if (!g_strcmp0(p, "ROLE"))
      display_vcard_item(barejid, "Role", vcard_attrib, data);
    else if (!g_strcmp0(p, "DESC"))
      display_vcard_item(barejid, "Comment", vcard_attrib, data);
    else if (!g_strcmp0(p, "N")) {
      data = lm_message_node_get_child_value(x, "FAMILY");
      display_vcard_item(barejid, "Family Name", vcard_attrib, data);
      data = lm_message_node_get_child_value(x, "GIVEN");
      display_vcard_item(barejid, "Given Name", vcard_attrib, data);
      data = lm_message_node_get_child_value(x, "MIDDLE");
      display_vcard_item(barejid, "Middle Name", vcard_attrib, data);
    } else if (!g_strcmp0(p, "ORG")) {
      data = lm_message_node_get_child_value(x, "ORGNAME");
      display_vcard_item(barejid, "Organisation name", vcard_attrib, data);
      data = lm_message_node_get_child_value(x, "ORGUNIT");
      display_vcard_item(barejid, "Organisation unit", vcard_attrib, data);
    } else {
      // The HOME, WORK and PREF attributes are common to the remaining fields
      // (ADR, TEL & EMAIL)
      if (lm_message_node_get_child(x, "HOME"))
        vcard_attrib |= vcard_home;
      if (lm_message_node_get_child(x, "WORK"))
        vcard_attrib |= vcard_work;
      if (lm_message_node_get_child(x, "PREF"))
        vcard_attrib |= vcard_pref;
      if (!g_strcmp0(p, "ADR")) {          // Address
        if (lm_message_node_get_child(x, "POSTAL"))
          vcard_attrib |= vcard_postal;
        data = lm_message_node_get_child_value(x, "EXTADD");
        display_vcard_item(barejid, "Addr (ext)", vcard_attrib, data);
        data = lm_message_node_get_child_value(x, "STREET");
        display_vcard_item(barejid, "Street", vcard_attrib, data);
        data = lm_message_node_get_child_value(x, "LOCALITY");
        display_vcard_item(barejid, "Locality", vcard_attrib, data);
        data = lm_message_node_get_child_value(x, "REGION");
        display_vcard_item(barejid, "Region", vcard_attrib, data);
        data = lm_message_node_get_child_value(x, "PCODE");
        display_vcard_item(barejid, "Postal code", vcard_attrib, data);
        data = lm_message_node_get_child_value(x, "CTRY");
        display_vcard_item(barejid, "Country", vcard_attrib, data);
      } else if (!g_strcmp0(p, "TEL")) {   // Telephone
        data = lm_message_node_get_child_value(x, "NUMBER");
        if (data) {
          if (lm_message_node_get_child(x, "VOICE"))
            vcard_attrib |= vcard_voice;
          if (lm_message_node_get_child(x, "FAX"))
            vcard_attrib |= vcard_fax;
          if (lm_message_node_get_child(x, "CELL"))
            vcard_attrib |= vcard_cell;
          display_vcard_item(barejid, "Phone", vcard_attrib, data);
        }
      } else if (!g_strcmp0(p, "EMAIL")) { // Email
        if (lm_message_node_get_child(x, "INTERNET"))
          vcard_attrib |= vcard_inet;
        data = lm_message_node_get_child_value(x, "USERID");
        display_vcard_item(barejid, "Email", vcard_attrib, data);
      }
    }
  }
}
Пример #5
0
static LmHandlerResult cb_time(LmMessageHandler *h, LmConnection *c,
                               LmMessage *m, gpointer user_data)
{
  LmMessageNode *ansqry;
  const char *p, *bjid;
  char *buf, *tmp;

  // Check IQ result sender
  bjid = lm_message_get_from(m);
  if (!bjid)
    bjid = lm_connection_get_jid(lconnection); // No from means our JID...
  if (!bjid) {
    scr_LogPrint(LPRINT_LOGNORM, "Invalid IQ:time result (no sender name).");
    return LM_HANDLER_RESULT_REMOVE_MESSAGE;
  }

  // Check for error message
  if (lm_message_get_sub_type(m) == LM_MESSAGE_SUB_TYPE_ERROR) {
    scr_LogPrint(LPRINT_LOGNORM, "Received error IQ message (%s)", bjid);
    display_server_error(lm_message_node_get_child(m->node, "error"), NULL);
    return LM_HANDLER_RESULT_REMOVE_MESSAGE;
  }

  // Check message contents
  ansqry = lm_message_node_get_child(m->node, "query");
  if (!ansqry) {
    scr_LogPrint(LPRINT_LOGNORM, "Invalid IQ:time result from <%s>!", bjid);
    return LM_HANDLER_RESULT_REMOVE_MESSAGE;
  }

  buf = g_strdup_printf("Received IQ:time result from <%s>", bjid);
  scr_LogPrint(LPRINT_LOGNORM, "%s", buf);

  // bjid should now really be the "bare JID", let's strip the resource
  tmp = strchr(bjid, JID_RESOURCE_SEPARATOR);
  if (tmp) *tmp = '\0';

  scr_WriteIncomingMessage(bjid, buf, 0, HBB_PREFIX_INFO, 0);
  g_free(buf);

  // Get result data...
  p = lm_message_node_get_child_value(ansqry, "utc");
  if (p && *p) {
    buf = g_strdup_printf("UTC:  %s", p);
    scr_WriteIncomingMessage(bjid, buf,
                             0, HBB_PREFIX_INFO | HBB_PREFIX_CONT, 0);
    g_free(buf);
  }
  p = lm_message_node_get_child_value(ansqry, "tz");
  if (p && *p) {
    buf = g_strdup_printf("TZ:   %s", p);
    scr_WriteIncomingMessage(bjid, buf,
                             0, HBB_PREFIX_INFO | HBB_PREFIX_CONT, 0);
    g_free(buf);
  }
  p = lm_message_node_get_child_value(ansqry, "display");
  if (p && *p) {
    buf = g_strdup_printf("Time: %s", p);
    scr_WriteIncomingMessage(bjid, buf,
                             0, HBB_PREFIX_INFO | HBB_PREFIX_CONT, 0);
    g_free(buf);
  }
  return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
Пример #6
0
// Specific MUC message handling (for example invitation processing)
void got_muc_message(const char *from, LmMessageNode *x, time_t timestamp)
{
  LmMessageNode *node;
  // invitation
  node = lm_message_node_get_child(x, "invite");
  if (node) {
    const char *invite_from;
    const char *reason = NULL;
    const char *password = NULL;

    invite_from = lm_message_node_get_attribute(node, "from");
    reason = lm_message_node_get_child_value(node, "reason");
    password = lm_message_node_get_child_value(node, "password");
    if (invite_from)
      got_invite(invite_from, from, reason, password, TRUE);
  }

  // declined invitation
  node = lm_message_node_get_child(x, "decline");
  if (node) {
    const char *decline_from = lm_message_node_get_attribute(node, "from");
    const char *reason = lm_message_node_get_child_value(node, "reason");
    if (decline_from) {
      if (reason && reason[0])
        scr_LogPrint(LPRINT_LOGNORM, "<%s> declined your invitation: %s.",
                     from, reason);
      else
        scr_LogPrint(LPRINT_LOGNORM, "<%s> declined your invitation.", from);
    }
  }

  // status codes
  for (node = x -> children; node; node = node -> next) {
    if (!g_strcmp0(node -> name, "status")) {
      const char *codestr = lm_message_node_get_attribute(node, "code");
      if (codestr) {
        const char *mesg = NULL;
        switch (atoi(codestr)) {
          // initial
          case 100:
                  mesg = "The room is not anonymous.";
                  break;
          case 101:
                  mesg = "Your affilation has changed while absent.";
                  break;
          case 102:
                  mesg = "The room shows unavailable members.";
                  break;
          case 103:
                  mesg = "The room does not show unavailable members.";
                  break;
          case 104:
                  mesg = "The room configuration has changed.";
                  break;
          case 170:
                  mesg = "The room is logged.";
                  break;
          case 171:
                  mesg = "The room is not logged.";
                  break;
          case 172:
                  mesg = "The room is not anonymous.";
                  break;
          case 173:
                  mesg = "The room is semi-anonymous.";
                  break;
          case 174:
                  mesg = "The room is anonymous.";
                  break;
          default:
                  scr_LogPrint(LPRINT_DEBUG,
                               "got_muc_message: Unknown MUC status code: %s.",
                               codestr);
                  break;
        }
        if (mesg) {
          scr_WriteIncomingMessage(from, mesg, timestamp,
                                   HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0);
        if (settings_opt_get_int("log_muc_conf"))
            hlog_write_message(from, 0, -1, mesg);
        }
      }
    }
  }
}
Пример #7
0
void handle_muc_presence(const char *from, LmMessageNode *xmldata,
                         const char *roomjid, const char *rname,
                         enum imstatus ust, const char *ustmsg,
                         time_t usttime, char bpprio)
{
  char *mbuf;
  const char *ournick;
  enum imrole mbrole = role_none;
  enum imaffiliation mbaffil = affil_none;
  enum room_printstatus printstatus;
  enum room_autowhois autowhois;
  enum room_flagjoins flagjoins;
  const char *mbjid = NULL, *mbnick = NULL;
  const char *reason = NULL;
  char *actor = NULL;
  bool new_member = FALSE; // True if somebody else joins the room (not us)
  bool our_presence = FALSE; // True if this presence is from us (i.e. bears
                             // code 110)
  guint statuscode = 0;
  guint nickchange = 0;
  GSList *room_elt;
  int log_muc_conf;
  guint msgflags;

  log_muc_conf = settings_opt_get_int("log_muc_conf");

  room_elt = roster_find(roomjid, jidsearch, 0);
  if (!room_elt) {
    // Add room if it doesn't already exist
    // It shouldn't happen, there is probably something wrong (server or
    // network issue?)
    room_elt = roster_add_user(roomjid, NULL, NULL, ROSTER_TYPE_ROOM,
                               sub_none, -1);
    scr_LogPrint(LPRINT_LOGNORM, "Strange MUC presence message");
  } else {
    // Make sure this is a room (it can be a conversion user->room)
    buddy_settype(room_elt->data, ROSTER_TYPE_ROOM);
  }

  // Get room member's information
  muc_get_item_info(from, xmldata, &mbrole, &mbaffil, &mbjid, &mbnick,
                    &actor, &reason);

  // Get our room nickname
  ournick = buddy_getnickname(room_elt->data);

  if (!ournick) {
    // It shouldn't happen, probably a server issue
    const gchar msg[] = "Unexpected groupchat packet!";
    scr_LogPrint(LPRINT_LOGNORM, msg);
    scr_WriteIncomingMessage(roomjid, msg, 0, HBB_PREFIX_INFO, 0);
    // Send back an unavailable packet
    xmpp_setstatus(offline, roomjid, "", TRUE);
    scr_draw_roster();
    return;
  }

#define SETSTATUSCODE(VALUE)                                              \
{                                                                         \
  if (G_UNLIKELY(statuscode))                                             \
    scr_LogPrint(LPRINT_DEBUG, "handle_muc_presence: WARNING: "           \
                 "replacing status code %u with %u.", statuscode, VALUE); \
  statuscode = VALUE;                                                     \
}

  { // Get the status code
    LmMessageNode *node;
    for (node = xmldata -> children; node; node = node -> next) {
      if (!g_strcmp0(node -> name, "status")) {
        const char *codestr = lm_message_node_get_attribute(node, "code");
        if (codestr) {
          const char *mesg = NULL;
          switch (atoi(codestr)) {
            // initial
            case 100:
                    mesg = "The room is not anonymous.";
                    break;
            case 110: // It is our presence
                    our_presence = TRUE;
                    break;
            // initial
            case 170:
                    mesg = "The room is logged.";
                    break;
            // initial
            case 201: // Room created
                    SETSTATUSCODE(201);
                    break;
            // initial
            case 210: // Your nick change (on join)
                    // FIXME: print nick
                    mesg = "The room has changed your nick!";
                    buddy_setnickname(room_elt->data, rname);
                    ournick = rname;
                    break;
            case 301: // User banned
                    SETSTATUSCODE(301);
                    break;
            case 303: // Nick change
                    SETSTATUSCODE(303);
                    break;
            case 307: // User kicked
                    SETSTATUSCODE(307);
                    break;
                    // XXX (next three)
            case 321:
                    mesg = "User leaves room due to affilation change.";
                    break;
            case 322:
                    mesg = "User leaves room, as room is only for members now.";
                    break;
            case 332:
                    mesg = "User leaves room due to system shutdown.";
                    break;
            default:
                    scr_LogPrint(LPRINT_DEBUG,
                           "handle_muc_presence: Unknown MUC status code: %s.",
                           codestr);
                    break;
          }
          if (mesg) {
            scr_WriteIncomingMessage(roomjid, mesg, usttime,
                                     HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0);
            if (log_muc_conf)
              hlog_write_message(roomjid, 0, -1, mesg);
          }
        }
      }
    }
  }

#undef SETSTATUSCODE

  if (!our_presence)
    if (ournick && !strcmp(ournick, rname))
      our_presence = TRUE;

  // Get the room's "print_status" settings
  printstatus = buddy_getprintstatus(room_elt->data);
  if (printstatus == status_default) {
    printstatus = (guint) settings_opt_get_int("muc_print_status");
    if (printstatus > 3)
      printstatus = status_default;
  }

  // A new room has been created; accept MUC default config
  if (statuscode == 201)
    xmpp_room_unlock(roomjid);

  // Check for nickname change
  if (statuscode == 303 && mbnick) {
    mbuf = g_strdup_printf("%s is now known as %s", rname, mbnick);
    scr_WriteIncomingMessage(roomjid, mbuf, usttime,
                             HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0);
    if (log_muc_conf)
      hlog_write_message(roomjid, 0, -1, mbuf);
    g_free(mbuf);
    buddy_resource_setname(room_elt->data, rname, mbnick);
    // Maybe it's _our_ nickname...
    if (our_presence)
      buddy_setnickname(room_elt->data, mbnick);
    nickchange = TRUE;
  }

  autowhois = buddy_getautowhois(room_elt->data);
  if (autowhois == autowhois_default)
    autowhois = (settings_opt_get_int("muc_auto_whois") ?
                 autowhois_on : autowhois_off);

  // Check for departure/arrival
  if (statuscode != 303 && ust == offline) {
    // Somebody is leaving
    enum { leave=0, kick, ban } how = leave;

    if (statuscode == 307)
      how = kick;
    else if (statuscode == 301)
      how = ban;

    // If this is a leave, check if it is ourself
    if (our_presence) {
      buddy_setinsideroom(room_elt->data, FALSE);
      buddy_setnickname(room_elt->data, NULL);
      buddy_del_all_resources(room_elt->data);
      buddy_settopic(room_elt->data, NULL);
      scr_update_chat_status(FALSE);
      update_roster = TRUE;
    }

    // The message depends on _who_ left, and _how_
    if (how) {
      gchar *mbuf_end;
      gchar *reason_msg = NULL;
      // Forced leave
      if (actor) {
        mbuf_end = g_strdup_printf("%s from %s by %s",
                                   (how == ban ? "banned" : "kicked"),
                                   roomjid, actor);
      } else {
        mbuf_end = g_strdup_printf("%s from %s",
                                   (how == ban ? "banned" : "kicked"),
                                   roomjid);
      }
      if (reason)
        reason_msg = g_strdup_printf("\nReason: %s", reason);
      if (our_presence)
        mbuf = g_strdup_printf("You have been %s%s", mbuf_end,
                               reason_msg ? reason_msg : "");
      else
        mbuf = g_strdup_printf("%s has been %s%s", rname, mbuf_end,
                               reason_msg ? reason_msg : "");

      g_free(reason_msg);
      g_free(mbuf_end);
    } else {
      // Natural leave
      if (our_presence) {
        LmMessageNode *destroynode = lm_message_node_find_child(xmldata,
                                                                "destroy");
        if (destroynode) {
          reason = lm_message_node_get_child_value(destroynode, "reason");
          if (reason && *reason) {
            mbuf = g_strdup_printf("You have left %s, "
                                   "the room has been destroyed: %s",
                                   roomjid, reason);
          } else {
            mbuf = g_strdup_printf("You have left %s, "
                                   "the room has been destroyed", roomjid);
          }
        } else {
          mbuf = g_strdup_printf("You have left %s", roomjid);
        }
      } else {
        if (ust != offline) {
          // This can happen when a network failure occurs,
          // this isn't an official leave but the user isn't there anymore.
          mbuf = g_strdup_printf("%s has disappeared!", rname);
          ust = offline;
        } else {
          if (ustmsg)
            mbuf = g_strdup_printf("%s has left: %s", rname, ustmsg);
          else
            mbuf = g_strdup_printf("%s has left", rname);
        }
      }
    }

    g_free(actor);

    // Display the mbuf message if we're concerned
    // or if the print_status isn't set to none.
    if (our_presence || printstatus != status_none) {
      msgflags = HBB_PREFIX_INFO;
      flagjoins = buddy_getflagjoins(room_elt->data);
      if (flagjoins == flagjoins_default &&
          settings_opt_get_int("muc_flag_joins") == 2)
	flagjoins = flagjoins_all;
      if (!our_presence && flagjoins != flagjoins_all)
        msgflags |= HBB_PREFIX_NOFLAG;
      //silent message if someone else joins, and we care about noone
      scr_WriteIncomingMessage(roomjid, mbuf, usttime, msgflags, 0);
    }

    if (log_muc_conf)
      hlog_write_message(roomjid, 0, -1, mbuf);

    if (our_presence) {
      scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf);
      g_free(mbuf);
      return;
    }
    g_free(mbuf);
  } else {
    enum imstatus old_ust = buddy_getstatus(room_elt->data, rname);
    if (old_ust == offline && ust != offline) {
      // Somebody is joining
      new_member = muc_handle_join(room_elt, rname, roomjid, ournick,
                                   printstatus, usttime, log_muc_conf,
                                   autowhois, mbjid);
    } else {
      // This is a simple member status change

      if (printstatus == status_all && !nickchange) {
        const char *old_ustmsg = buddy_getstatusmsg(room_elt->data, rname);
        if (old_ust != ust || g_strcmp0(old_ustmsg, ustmsg)) {
          mbuf = g_strdup_printf("%s [%c>%c] %s", rname, imstatus2char[old_ust],
                                 imstatus2char[ust], ((ustmsg) ? ustmsg : ""));
          scr_WriteIncomingMessage(roomjid, mbuf, usttime,
                                 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0);
          g_free(mbuf);
        }
      }
    }
  }

  // Sanity check, shouldn't happen...
  if (!rname)
    return;

  // Update room member status
  roster_setstatus(roomjid, rname, bpprio, ust, ustmsg, usttime,
                   mbrole, mbaffil, mbjid);

  if (new_member && autowhois == autowhois_on) {
    cmd_room_whois(room_elt->data, rname, FALSE);
  }

  scr_draw_roster();
}