#include #include #include #include #define SERVER "whatevermaybe.net" #define ROOM_JID "archlinux@chat.hax.al" #define BOT_NICKNAME "erdhe" #define BOT_JID "bot@hax.al" #define BOT_PASSWORD "passwordfield" /* Add UNUSED macro to suppress warnings */ #define UNUSED(x) (void)(x) /* List to track users who have already received the whisper */ typedef struct UserList { char **users; int count; int size; } UserList; /* Global user list */ UserList userlist; /* Flag to determine whether the bot has finished joining the room */ int bot_joined = 0; /* Add user to list */ void userlist_add(UserList *list, const char *jid) { if (list->count >= list->size) { list->size *= 2; list->users = realloc(list->users, list->size * sizeof(char *)); } list->users[list->count] = strdup(jid); list->count++; } /* Check if user is in the list */ int userlist_contains(UserList *list, const char *jid) { for (int i = 0; i < list->count; i++) { if (strcmp(list->users[i], jid) == 0) { return 1; } } return 0; } /* Send a whisper message */ void send_whisper(xmpp_conn_t * const conn, xmpp_ctx_t *ctx, const char *to_jid, const char *message) { xmpp_stanza_t *msg = xmpp_stanza_new(ctx); xmpp_stanza_set_name(msg, "message"); xmpp_stanza_set_type(msg, "chat"); xmpp_stanza_set_attribute(msg, "to", to_jid); xmpp_stanza_t *body = xmpp_stanza_new(ctx); xmpp_stanza_set_name(body, "body"); xmpp_stanza_t *text = xmpp_stanza_new(ctx); xmpp_stanza_set_text(text, message); xmpp_stanza_add_child(body, text); xmpp_stanza_add_child(msg, body); xmpp_stanza_release(text); xmpp_stanza_release(body); xmpp_send(conn, msg); xmpp_stanza_release(msg); fprintf(stderr, "Sent whisper to %s: %s\n", to_jid, message); } /* Handle presence stanzas */ int presence_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *from = xmpp_stanza_get_attribute(stanza, "from"); // Fix const issue xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; /* Ensure the presence is related to the room */ if (from && strstr(from, ROOM_JID)) { const char *resource = strchr(from, '/'); if (resource && strcmp(resource + 1, BOT_NICKNAME) != 0) { // Ignore presence from the bot itself /* Send whisper only if the bot has fully joined and user hasn't received it before */ if (bot_joined && !userlist_contains(&userlist, from)) { send_whisper(conn, ctx, from, "Welcome to the room!"); userlist_add(&userlist, from); } else { /* Add user to the list if the bot is still joining */ userlist_add(&userlist, from); } } } return 1; } /* Handle connection events */ void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status, const int error, xmpp_stream_error_t * const stream_error, void * const userdata) { xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; if (status == XMPP_CONN_CONNECT) { fprintf(stderr, "Connected to server %s\n", SERVER); /* Add handler for presence stanzas */ xmpp_handler_add(conn, presence_handler, NULL, "presence", NULL, ctx); /* Create presence stanza to join room */ xmpp_stanza_t *presence = xmpp_stanza_new(ctx); xmpp_stanza_set_name(presence, "presence"); /* Set the "to" attribute as room_jid/nickname */ char to_buffer[512]; snprintf(to_buffer, sizeof(to_buffer), "%s/%s", ROOM_JID, BOT_NICKNAME); xmpp_stanza_set_attribute(presence, "to", to_buffer); /* Add MUC namespace */ xmpp_stanza_t *x = xmpp_stanza_new(ctx); xmpp_stanza_set_name(x, "x"); xmpp_stanza_set_ns(x, "http://jabber.org/protocol/muc"); xmpp_stanza_add_child(presence, x); xmpp_stanza_release(x); /* Send presence stanza */ xmpp_send(conn, presence); xmpp_stanza_release(presence); fprintf(stderr, "Sent presence to join room: %s\n", to_buffer); /* Mark the bot as fully joined after the initial presence handling */ bot_joined = 1; } else { if (error) { fprintf(stderr, "Connection error: %d\n", error); if (stream_error) { fprintf(stderr, "Stream error type: %d\n", stream_error->type); } } fprintf(stderr, "Disconnected from server\n"); xmpp_stop(ctx); } } /* Main function */ int main(void) { xmpp_ctx_t *ctx; xmpp_conn_t *conn; xmpp_log_t *log; /* Initialize userlist */ userlist.size = 10; // Initial size userlist.count = 0; userlist.users = malloc(userlist.size * sizeof(char *)); xmpp_initialize(); log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); /* Use default logger instead of creating new one */ ctx = xmpp_ctx_new(NULL, log); conn = xmpp_conn_new(ctx); xmpp_conn_set_jid(conn, BOT_JID); xmpp_conn_set_pass(conn, BOT_PASSWORD); /* Explicitly set the server */ xmpp_conn_set_flags(conn, XMPP_CONN_FLAG_MANDATORY_TLS); fprintf(stderr, "Connecting to %s...\n", SERVER); if (xmpp_connect_client(conn, SERVER, 0, conn_handler, ctx) == XMPP_EOK) { fprintf(stderr, "Running connection...\n"); xmpp_run(ctx); } else { fprintf(stderr, "Failed to start connection\n"); } xmpp_conn_release(conn); xmpp_ctx_free(ctx); xmpp_shutdown(); /* Free the userlist */ for (int i = 0; i < userlist.count; i++) { free(userlist.users[i]); } free(userlist.users); return 0; }