Ejemplo n.º 1
0
LmHandlerResult handle_iq_last(LmMessageHandler *h, LmConnection *c,
                               LmMessage *m, gpointer ud)
{
  LmMessage *r;
  LmMessageNode *query;
  char *seconds;

  if (!settings_opt_get_int("iq_hide_requests")) {
    scr_LogPrint(LPRINT_LOGNORM, "Received an IQ last time request from <%s>",
                 lm_message_get_from(m));
  }

  if (settings_opt_get_int("iq_last_disable") ||
      (settings_opt_get_int("iq_last_disable_when_notavail") &&
       xmpp_getstatus() == notavail))
  {
    send_iq_error(c, m, XMPP_ERROR_SERVICE_UNAVAILABLE);
    return LM_HANDLER_RESULT_REMOVE_MESSAGE;
  }

  r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT);
  query = lm_message_node_add_child(r->node, "query", NULL);
  lm_message_node_set_attribute(query, "xmlns", NS_LAST);
  seconds = g_strdup_printf("%.0f", seconds_since_last_use());
  lm_message_node_set_attribute(query, "seconds", seconds);
  g_free(seconds);

  lm_connection_send(c, r, NULL);
  lm_message_unref(r);
  return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
Ejemplo n.º 2
0
// This function borrows some code from the Pidgin project
LmHandlerResult handle_iq_time(LmMessageHandler *h, LmConnection *c,
                               LmMessage *m, gpointer ud)
{
  LmMessage *r;
  LmMessageNode *query;
  char *buf, *utf8_buf;
  time_t now_t;
  struct tm *now;

  time(&now_t);

  if (!settings_opt_get_int("iq_hide_requests")) {
    scr_LogPrint(LPRINT_LOGNORM, "Received an IQ time request from <%s>",
                 lm_message_get_from(m));
  }

  if (settings_opt_get_int("iq_time_hide")) {
    send_iq_error(c, m, XMPP_ERROR_SERVICE_UNAVAILABLE);
    return LM_HANDLER_RESULT_REMOVE_MESSAGE;
  }

  buf = g_new0(char, 512);

  r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT);
  query = lm_message_node_add_child(r->node, "query", NULL);
  lm_message_node_set_attribute(query, "xmlns", NS_TIME);

  now = gmtime(&now_t);

  strftime(buf, 512, "%Y%m%dT%T", now);
  lm_message_node_add_child(query, "utc", buf);

  now = localtime(&now_t);

  strftime(buf, 512, "%Z", now);
  if ((utf8_buf = to_utf8(buf))) {
    lm_message_node_add_child(query, "tz", utf8_buf);
    g_free(utf8_buf);
  }

  strftime(buf, 512, "%d %b %Y %T", now);
  if ((utf8_buf = to_utf8(buf))) {
    lm_message_node_add_child(query, "display", utf8_buf);
    g_free(utf8_buf);
  }

  lm_connection_send(c, r, NULL);
  lm_message_unref(r);
  g_free(buf);
  return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
Ejemplo n.º 3
0
// This function borrows some code from the Pidgin project
LmHandlerResult handle_iq_time202(LmMessageHandler *h, LmConnection *c,
                                  LmMessage *m, gpointer ud)
{
  LmMessage *r;
  LmMessageNode *query;
  char *buf, *utf8_buf;
  time_t now_t;
  struct tm *now;
  char const *sign;
  int diff = 0;

  time(&now_t);

  if (!settings_opt_get_int("iq_hide_requests")) {
    scr_LogPrint(LPRINT_LOGNORM, "Received an IQ time request from <%s>",
                 lm_message_get_from(m));
  }

  buf = g_new0(char, 512);

  r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT);
  query = lm_message_node_add_child(r->node, "time", NULL);
  lm_message_node_set_attribute(query, "xmlns", NS_XMPP_TIME);

  now = localtime(&now_t);

  if (now->tm_isdst >= 0) {
#if defined HAVE_TM_GMTOFF
    diff = now->tm_gmtoff;
#elif defined HAVE_TIMEZONE
    tzset();
    diff = -timezone;
#endif
  }

  if (diff < 0) {
    sign = "-";
    diff = -diff;
  } else {
    sign = "+";
  }
  diff /= 60;
  snprintf(buf, 512, "%c%02d:%02d", *sign, diff / 60, diff % 60);
  if ((utf8_buf = to_utf8(buf))) {
    lm_message_node_add_child(query, "tzo", utf8_buf);
    g_free(utf8_buf);
  }

  now = gmtime(&now_t);

  strftime(buf, 512, "%Y-%m-%dT%TZ", now);
  lm_message_node_add_child(query, "utc", buf);

  lm_connection_send(c, r, NULL);
  lm_message_unref(r);
  g_free(buf);
  return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
Ejemplo n.º 4
0
LmHandlerResult handle_iq_version(LmMessageHandler *h, LmConnection *c,
                                  LmMessage *m, gpointer ud)
{
  LmMessage *r;
  LmMessageNode *query;

  if (!settings_opt_get_int("iq_hide_requests")) {
    scr_LogPrint(LPRINT_LOGNORM, "Received an IQ version request from <%s>",
                 lm_message_get_from(m));
  }

  if (settings_opt_get_int("iq_version_hide")) {
    send_iq_error(c, m, XMPP_ERROR_SERVICE_UNAVAILABLE);
    return LM_HANDLER_RESULT_REMOVE_MESSAGE;
  }

  r = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT);

  query = lm_message_node_add_child(r->node, "query", NULL);
  lm_message_node_set_attribute(query, "xmlns", NS_VERSION);

  lm_message_node_add_child(query, "name", PACKAGE_NAME);

  // MCabber version
  if (!settings_opt_get_int("iq_version_hide_version")) {
    char *ver = mcabber_version();
    lm_message_node_add_child(query, "version", ver);
    g_free(ver);
  }

  // OS details
  if (!settings_opt_get_int("iq_version_hide_os")) {
    char *os;
    struct utsname osinfo;
    uname(&osinfo);
    os = g_strdup_printf("%s %s %s", osinfo.sysname, osinfo.release,
                         osinfo.machine);
    lm_message_node_add_child(query, "os", os);
    g_free(os);
  }

  lm_connection_send(c, r, NULL);
  lm_message_unref(r);
  return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
Ejemplo n.º 5
0
static guint fifo_callback(GIOChannel *channel,
                           GIOCondition condition,
                           gpointer data)
{
  if (condition & (G_IO_IN|G_IO_PRI)) {
    GIOStatus  chstat;
    gchar     *buf;
    gsize      endpos;

    chstat = g_io_channel_read_line(channel, &buf, NULL, &endpos, NULL);
    if (chstat == G_IO_STATUS_ERROR || chstat == G_IO_STATUS_EOF) {
      if (!attach_fifo(fifo_name))
        scr_LogPrint(LPRINT_LOGNORM,
                     "Reopening fifo failed! Fifo will not work from now!");
      return FALSE;
    }
    if (buf) {
      guint logflag;
      guint fifo_ignore = settings_opt_get_int("fifo_ignore");

      if (endpos)
        buf[endpos] = '\0';

      if (settings_opt_get_int("fifo_hide_commands"))
        logflag = LPRINT_LOG;
      else
        logflag = LPRINT_LOGNORM;
      scr_LogPrint(logflag, "%s FIFO command: %s",
                   (fifo_ignore ? "Ignoring" : "Executing"), buf);
      if (!fifo_ignore) {
        process_command(buf, TRUE);
      }

      g_free(buf);
    }
  } else if (condition & (G_IO_ERR|G_IO_NVAL|G_IO_HUP)) {
    if (!attach_fifo(fifo_name))
      scr_LogPrint(LPRINT_LOGNORM,
                   "Reopening fifo failed! Fifo will not work from now!");
    return FALSE;
  }
  return TRUE;
}
Ejemplo n.º 6
0
LmHandlerResult handle_iq_roster(LmMessageHandler *h, LmConnection *c,
                                 LmMessage *m, gpointer ud)
{
  LmMessageNode *y;
  const char *fjid, *name, *group, *sub, *ask;
  char *cleanalias;
  enum subscr esub;
  int need_refresh = FALSE;
  guint roster_type;

  y = lm_message_node_find_child(lm_message_node_find_xmlns(m->node, NS_ROSTER),
                                 "item");
  for ( ; y; y = y->next) {
    char *name_tmp = NULL;

    fjid = lm_message_node_get_attribute(y, "jid");
    name = lm_message_node_get_attribute(y, "name");
    sub = lm_message_node_get_attribute(y, "subscription");
    ask = lm_message_node_get_attribute(y, "ask");

    if (lm_message_node_find_child(y, "group"))
      group = lm_message_node_get_value(lm_message_node_find_child(y, "group"));
    else
      group = NULL;

    if (!fjid)
      continue;

    cleanalias = jidtodisp(fjid);

    esub = sub_none;
    if (sub) {
      if (!strcmp(sub, "to"))          esub = sub_to;
      else if (!strcmp(sub, "from"))   esub = sub_from;
      else if (!strcmp(sub, "both"))   esub = sub_both;
      else if (!strcmp(sub, "remove")) esub = sub_remove;
    }

    if (esub == sub_remove) {
      roster_del_user(cleanalias);
      scr_LogPrint(LPRINT_LOGNORM, "Buddy <%s> has been removed "
                   "from the roster", cleanalias);
      g_free(cleanalias);
      need_refresh = TRUE;
      continue;
    }

    if (ask && !strcmp(ask, "subscribe"))
      esub |= sub_pending;

    if (!name) {
      if (!settings_opt_get_int("roster_hide_domain")) {
        name = cleanalias;
      } else {
        char *p;
        name = name_tmp = g_strdup(cleanalias);
        p = strchr(name_tmp, JID_DOMAIN_SEPARATOR);
        if (p)  *p = '\0';
      }
    }

    // Tricky... :-\  My guess is that if there is no JID_DOMAIN_SEPARATOR,
    // this is an agent.
    if (strchr(cleanalias, JID_DOMAIN_SEPARATOR))
      roster_type = ROSTER_TYPE_USER;
    else
      roster_type = ROSTER_TYPE_AGENT;

    roster_add_user(cleanalias, name, group, roster_type, esub, 1);

    g_free(name_tmp);
    g_free(cleanalias);
  }

  // Acknowledge IQ message
  if (lm_message_get_sub_type(m) == LM_MESSAGE_SUB_TYPE_SET) {
    LmMessage *result;
    result = lm_message_new_iq_from_query(m, LM_MESSAGE_SUB_TYPE_RESULT);
    lm_connection_send(c, result, NULL);
    lm_message_unref(result);
  }

  buddylist_build();
  update_roster = TRUE;
  if (need_refresh)
    scr_update_buddy_window();
  return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
Ejemplo n.º 7
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);
        }
      }
    }
  }
}
Ejemplo n.º 8
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();
}
Ejemplo n.º 9
0
//  muc_handle_join(...)
// Handle a join event in a MUC room.
// This function will return the new_member value TRUE if somebody else joins
// the room (and FALSE if _we_ are joining the room).
static bool muc_handle_join(const GSList *room_elt, const char *rname,
                            const char *roomjid, const char *ournick,
                            enum room_printstatus printstatus,
                            time_t usttime, int log_muc_conf,
                            enum room_autowhois autowhois, const char *mbjid)
{
  bool new_member = FALSE; // True if somebody else joins the room (not us)
  gchar *nickjid;
  gchar *mbuf;
  enum room_flagjoins flagjoins;
  char *tmp = NULL;
  int printjid;

  printjid = settings_opt_get_int("muc_print_jid");
  if (mbjid && autowhois == autowhois_off && printjid) {
    if (printjid == 1)
      tmp = strchr(mbjid, JID_RESOURCE_SEPARATOR);
    if (tmp) *tmp = '\0';
    nickjid = g_strdup_printf("%s <%s>", rname, mbjid);
    if (tmp) *tmp = JID_RESOURCE_SEPARATOR;
  } else {
    nickjid = g_strdup(rname);
  }

  if (!buddy_getinsideroom(room_elt->data)) {
    // We weren't inside the room yet.  Now we are.
    // However, this could be a presence packet from another room member

    buddy_setinsideroom(room_elt->data, TRUE);
    // Set the message flag unless we're already in the room buffer window
    scr_setmsgflag_if_needed(roomjid, FALSE);
    // Add a message to the tracelog file
    mbuf = g_strdup_printf("You have joined %s as \"%s\"", roomjid, ournick);
    scr_LogPrint(LPRINT_LOGNORM, "%s", mbuf);
    g_free(mbuf);
    mbuf = g_strdup_printf("You have joined as \"%s\"", ournick);

    // The 1st presence message could be for another room member
    if (strcmp(ournick, rname)) {
      // Display current mbuf and create a new message for the member
      // Note: the usttime timestamp is related to the other member,
      //       so we use 0 here.
      scr_WriteIncomingMessage(roomjid, mbuf, 0,
                               HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0);
      if (log_muc_conf)
        hlog_write_message(roomjid, 0, -1, mbuf);
      g_free(mbuf);
      if (printstatus != status_none)
        mbuf = g_strdup_printf("%s has joined", nickjid);
      else
        mbuf = NULL;
      new_member = TRUE;
    }
  } else {
    mbuf = NULL;
    if (strcmp(ournick, rname)) {
      if (printstatus != status_none)
        mbuf = g_strdup_printf("%s has joined", nickjid);
      new_member = TRUE;
    }
  }

  g_free(nickjid);

  if (mbuf) {
    guint msgflags = HBB_PREFIX_INFO;
    flagjoins = buddy_getflagjoins(room_elt->data);
    if (flagjoins == flagjoins_default &&
        !settings_opt_get_int("muc_flag_joins"))
      flagjoins = flagjoins_none;
    if (flagjoins == flagjoins_none)
      msgflags |= HBB_PREFIX_NOFLAG;
    scr_WriteIncomingMessage(roomjid, mbuf, usttime, msgflags, 0);
    if (log_muc_conf)
      hlog_write_message(roomjid, 0, -1, mbuf);
    g_free(mbuf);
  }

  return new_member;
}