void query_init(QUERY_REC *query, int automatic) { g_return_if_fail(query != NULL); g_return_if_fail(query->name != NULL); queries = g_slist_append(queries, query); MODULE_DATA_INIT(query); query->type = module_get_uniq_id_str("WINDOW ITEM TYPE", "QUERY"); query->destroy = (void (*) (WI_ITEM_REC *)) query_destroy; query->get_target = query_get_target; query->createtime = time(NULL); query->last_unread_msg = time(NULL); query->visible_name = g_strdup(query->name); if (query->server_tag != NULL) { query->server = server_find_tag(query->server_tag); if (query->server != NULL) { query->server->queries = g_slist_append(query->server->queries, query); } } signal_emit("query created", 2, query, GINT_TO_POINTER(automatic)); }
/* `optlist' should contain only one unknown key - the server tag. returns NULL if there was unknown -option */ SERVER_REC *cmd_options_get_server(const char *cmd, GHashTable *optlist, SERVER_REC *defserver) { SERVER_REC *server; GList *list; /* get all the options, then remove the known ones. there should be only one left - the server tag. */ list = optlist_remove_known(cmd, optlist); if (list == NULL) return defserver; server = server_find_tag(list->data); if (server == NULL || list->next != NULL) { /* unknown option (not server tag) */ signal_emit("error command", 2, GINT_TO_POINTER(CMDERR_OPTION_UNKNOWN), server == NULL ? list->data : list->next->data); signal_stop(); server = NULL; } g_list_free(list); return server; }
static int sig_autoremove(void) { SERVER_REC *server; LOG_ITEM_REC *logitem; GSList *tmp, *next; time_t removetime; removetime = time(NULL)-AUTOLOG_INACTIVITY_CLOSE; for (tmp = logs; tmp != NULL; tmp = next) { LOG_REC *log = tmp->data; next = tmp->next; if (!log->temp || log->last > removetime || log->items == NULL) continue; /* Close only logs with private messages */ logitem = log->items->data; if (logitem->servertag == NULL) continue; server = server_find_tag(logitem->servertag); if (logitem->type == LOG_ITEM_TARGET && server != NULL && !server_ischannel(server, logitem->name)) log_close(log); } return 1; }
/* * putserv_raw tcl interp command * * all command parameters should be using unicode (internal) encoding. * * TODO: Any output from this command will not be seen on Irssi side */ int putserv_raw(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { (void) clientData; if (objc != 3) { Tcl_Obj* str = Tcl_ObjPrintf("wrong # args: should be \"putserv_raw" " server_tag text\""); Tcl_SetObjResult(interp, str); return TCL_ERROR; } Tcl_Obj* const server_tag = objv[1]; Tcl_Obj* const text = objv[2]; // find the Irssi server with the given tag. SERVER_REC* server = server_find_tag(Tcl_GetString(server_tag)); if (server == NULL) { Tcl_Obj* str = Tcl_ObjPrintf("server with tag '%s' not found", Tcl_GetString(server_tag)); Tcl_SetObjResult(interp, str); return TCL_ERROR; } irc_send_cmd((IRC_SERVER_REC*) server, Tcl_GetString(text)); return TCL_OK; }
/* server connect <servertag> */ bool cfg_conf_server_connect(struct cfg_state *cmd, char *args) { int fields = countfields(args); char tag[25], var[25], val[1000]; struct server *srv; struct channel *ch; /* Add requires 1 variables */ if ( fields != 1 || !copyfield(args, 1, tag, sizeof(tag))) { sock_printf(cmd->sock, "400 The command is: server connect <servertag>\n"); return false; } srv = server_find_tag(tag); if (!srv) { sock_printf(cmd->sock, "400 Server '%s' does not exist\n"); return false; } server_connect(srv); sock_printf(cmd->sock, "200 Connecting to server\n"); return true; }
/* * Emit a message public event * Does not actually send anything to the server, only to the client */ int emit_message_public(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { (void) clientData; // emit_message_public <server> <channel> <nick> <address> <text> if (objc != 6) { Tcl_Obj* str = Tcl_ObjPrintf("wrong # args: should be" " \"emit_message_public server channel nick address text\""); Tcl_SetObjResult(interp, str); return TCL_ERROR; } Tcl_Obj* const server_tag = objv[1]; Tcl_Obj* const chan = objv[2]; Tcl_Obj* const nick = objv[3]; Tcl_Obj* const addr = objv[4]; Tcl_Obj* const text = objv[5]; // find the Irssi server by tag. SERVER_REC* server = server_find_tag(Tcl_GetString(server_tag)); if (server == NULL) { Tcl_Obj* str = Tcl_ObjPrintf("server with tag '%s' not found", Tcl_GetString(server_tag)); Tcl_SetObjResult(interp, str); return TCL_ERROR; } signal_emit("message public", 5, server, Tcl_GetString(text), Tcl_GetString(nick), Tcl_GetString(addr), Tcl_GetString(chan)); return TCL_OK; }
static void dcc_queue_send_next(int queue) { IRC_SERVER_REC *server; DCC_QUEUE_REC *qrec; int send_started = FALSE; while ((qrec = dcc_queue_get_next(queue)) != NULL && !send_started) { server = qrec->servertag == NULL ? NULL : IRC_SERVER(server_find_tag(qrec->servertag)); if (server == NULL && qrec->chat == NULL) { /* no way to send this request */ signal_emit("dcc error send no route", 2, qrec->nick, qrec->file); } else { send_started = dcc_send_one_file(queue, qrec->nick, qrec->file, server, qrec->chat); } dcc_queue_remove_head(queue); } if (!send_started) { /* no files in queue anymore, remove it */ dcc_queue_free(queue); } }
static Server *tag_get_server(GtkTextTag *tag) { /* "nick <server tag>" */ if (strncmp(tag->name, "nick ", 5) != 0) return NULL; return server_find_tag(tag->name+5); }
/* SYNTAX: WINDOW SERVER [-sticky | -unsticky] <tag> */ static void cmd_window_server(const char *data) { GHashTable *optlist; SERVER_REC *server; char *tag; void *free_arg; if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS, "window server", &optlist, &tag)) return; if (*tag == '\0' && active_win->active_server != NULL && (g_hash_table_lookup(optlist, "sticky") != NULL || g_hash_table_lookup(optlist, "unsticky") != NULL)) { tag = active_win->active_server->tag; } if (*tag == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); server = server_find_tag(tag); if (server == NULL) server = server_find_lookup_tag(tag); if (g_hash_table_lookup(optlist, "unsticky") != NULL && active_win->servertag != NULL) { g_free_and_null(active_win->servertag); printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, TXT_UNSET_SERVER_STICKY); } if (active_win->servertag != NULL && g_hash_table_lookup(optlist, "sticky") == NULL) { printformat_window(active_win, MSGLEVEL_CLIENTERROR, TXT_ERROR_SERVER_STICKY); } else if (server == NULL) { printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, TXT_UNKNOWN_SERVER_TAG, tag); } else if (active_win->active == NULL) { window_change_server(active_win, server); if (g_hash_table_lookup(optlist, "sticky") != NULL) { g_free_not_null(active_win->servertag); active_win->servertag = g_strdup(server->tag); printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, TXT_SET_SERVER_STICKY, server->tag); } printformat_window(active_win, MSGLEVEL_CLIENTNOTICE, TXT_SERVER_CHANGED, server->tag, server->connrec->address, server->connrec->chatnet == NULL ? "" : server->connrec->chatnet); } cmd_params_free(free_arg); }
/* create unique tag for server. prefer ircnet's name or generate it from server's address */ static char *server_create_tag(SERVER_CONNECT_REC *conn) { GString *str; char *tag; int num; g_return_val_if_fail(IS_SERVER_CONNECT(conn), NULL); tag = conn->chatnet != NULL && *conn->chatnet != '\0' ? g_strdup(conn->chatnet) : server_create_address_tag(conn->address); if (conn->tag != NULL && server_find_tag(conn->tag) == NULL && server_find_lookup_tag(conn->tag) == NULL && strncmp(conn->tag, tag, strlen(tag)) == 0) { /* use the existing tag if it begins with the same ID - this is useful when you have several connections to same server and you want to keep the same tags with the servers (or it would cause problems when rejoining /LAYOUT SAVEd channels). */ g_free(tag); return g_strdup(conn->tag); } /* then just append numbers after tag until unused is found.. */ str = g_string_new(tag); num = 2; while (server_find_tag(str->str) != NULL || server_find_lookup_tag(str->str) != NULL) { g_string_sprintf(str, "%s%d", tag, num); num++; } g_free(tag); tag = str->str; g_string_free(str, FALSE); return tag; }
/* server add <servertag> <RFC1459|Timestamp|P10|User|BitlBee> <hostname> <service|portnumber> <nickname|none> <localname> <password|none> <identity> */ bool cfg_conf_server_add(struct cfg_state *cmd, char *args) { int fields = countfields(args); char tag[25], type[10], hostname[24], service[24], nick[24], local[24], pass[24], identity[24]; enum srv_types typ = SRV_BITLBEE; /* Add requires 8 variables */ if ( fields != 8 || !copyfield(args, 1, tag, sizeof(tag)) || !copyfield(args, 2, type, sizeof(type)) || !copyfield(args, 3, hostname, sizeof(hostname)) || !copyfield(args, 4, service, sizeof(service)) || !copyfield(args, 5, nick, sizeof(nick)) || !copyfield(args, 6, local, sizeof(local)) || !copyfield(args, 7, pass, sizeof(pass)) || !copyfield(args, 8, identity, sizeof(identity))) { sock_printf(cmd->sock, "400 The command is: server add <servertag> <RFC1459|Timestamp|P10|User|BitlBee> <hostname> <service|portnumber> <nickname|none> <localname> <password> <identity>\n"); return false; } if ( strcasecmp(type, "rfc1459" ) == 0) typ = SRV_RFC1459; else if (strcasecmp(type, "timestamp" ) == 0) typ = SRV_TS; else if (strcasecmp(type, "bitlbee" ) == 0) typ = SRV_BITLBEE; else if (strcasecmp(type, "user" ) == 0) typ = SRV_USER; else { sock_printf(cmd->sock, "400 '%s' is an unsupported server type\n", type); return false; } if (server_find_tag(tag)) { sock_printf(cmd->sock, "400 Server '%s' already exists\n", tag); return false; } if (server_add(tag, typ, hostname, service, strcasecmp(nick, "none") == 0 ? NULL : nick, local, strcasecmp(pass, "none") == 0 ? NULL : pass, identity, g_conf->service_description)) { sock_printf(cmd->sock, "200 Added server %s\n", tag); return true; } sock_printf(cmd->sock, "400 Server addition failed\n"); return false; }
/* SYNTAX: WINDOW SERVER <tag> */ static void cmd_window_server(const char *data) { SERVER_REC *server; g_return_if_fail(data != NULL); server = server_find_tag(data); if (server == NULL) printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_UNKNOWN_SERVER_TAG, data); else if (active_win->active == NULL) { window_change_server(active_win, server); printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_SERVER_CHANGED, server->tag, server->connrec->address, server->connrec->chatnet == NULL ? "" : server->connrec->chatnet); } }
static SERVER_REC *line_get_server(const char *line) { SERVER_REC *server; char *tag, *ptr; g_return_val_if_fail(line != NULL, NULL); if (*line != '-') return NULL; /* -option found - should be server tag */ tag = g_strdup(line+1); ptr = strchr(tag, ' '); if (ptr != NULL) *ptr = '\0'; server = server_find_tag(tag); g_free(tag); return server; }
/* * Similar to emit_message_public() in that the public message will be * printed to the Irssi screen as though it is a public message, but this * one does not cause an Irssi signal to be sent. */ int print_message_public_tcl(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { (void) clientData; // print_message_public <server> <channel> <nick> <address> <text> if (objc != 6) { Tcl_Obj* str = Tcl_ObjPrintf("wrong # args: should be" " \"print_message_public server channel nick address text \""); Tcl_SetObjResult(interp, str); return TCL_ERROR; } Tcl_Obj* const server_tag = objv[1]; // channel = target Tcl_Obj* const target = objv[2]; Tcl_Obj* const nick = objv[3]; Tcl_Obj* const address = objv[4]; Tcl_Obj* const msg = objv[5]; // find the Irssi server by tag. SERVER_REC* server_rec = server_find_tag(Tcl_GetString(server_tag)); if (server_rec == NULL) { Tcl_Obj* str = Tcl_ObjPrintf("server with tag '%s' not found", Tcl_GetString(server_tag)); Tcl_SetObjResult(interp, str); return TCL_ERROR; } // find the channel on the server. CHANNEL_REC* channel_rec = channel_find(server_rec, Tcl_GetString(target)); if (channel_rec == NULL) { Tcl_Obj* str = Tcl_ObjPrintf("channel '%s' not found on server '%s'", Tcl_GetString(target), Tcl_GetString(server_tag)); Tcl_SetObjResult(interp, str); return TCL_ERROR; } print_message_public(server_rec, channel_rec, Tcl_GetString(target), Tcl_GetString(nick), Tcl_GetString(address), Tcl_GetString(msg)); return TCL_OK; }
static void cmd_window_server(const char *data) { SERVER_REC *server; g_return_if_fail(data != NULL); server = server_find_tag(data); if (irc_server_check(server) && irc_item_query(active_win->active)) { /* /WINDOW SERVER used in a query window */ query_change_server((QUERY_REC *) active_win->active, (IRC_SERVER_REC *) server); window_change_server(active_win, server); printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_QUERY_SERVER_CHANGED, server->tag, server->connrec->address, server->connrec->ircnet == NULL ? "" : server->connrec->ircnet); signal_stop(); } }
void query_init(QUERY_REC *query, int automatic) { g_return_if_fail(query != NULL); g_return_if_fail(query->name != NULL); queries = g_slist_append(queries, query); MODULE_DATA_INIT(query); query->type = module_get_uniq_id_str("WINDOW ITEM TYPE", "QUERY"); if (query->server_tag != NULL) { query->server = server_find_tag(query->server_tag); if (query->server != NULL) { query->server->queries = g_slist_append(query->server->queries, query); } } signal_emit("query created", 2, query, GINT_TO_POINTER(automatic)); }
static void cmd_window_server(const char *data) { SERVER_REC *server; QUERY_REC *query; g_return_if_fail(data != NULL); server = server_find_tag(data); query = QUERY(active_win->active); if (server == NULL || query == NULL) return; /* /WINDOW SERVER used in a query window */ query_change_server(query, server); printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_QUERY_SERVER_CHANGED, query->name, server->tag); signal_stop(); }
/* SYNTAX: DISCONNECT *|<tag> [<message>] */ static void cmd_disconnect(const char *data, SERVER_REC *server) { char *tag, *msg; void *free_arg; g_return_if_fail(data != NULL); if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &tag, &msg)) return; if (*tag != '\0' && strcmp(tag, "*") != 0) { server = server_find_tag(tag); if (server == NULL) server = server_find_lookup_tag(tag); } if (server == NULL) cmd_param_error(CMDERR_NOT_CONNECTED); if (*msg == '\0') msg = (char *) settings_get_str("quit_message"); signal_emit("server quit", 2, server, msg); cmd_params_free(free_arg); server_disconnect(server); }
/* `optlist' should contain only one unknown key - the server tag. returns NULL if there was unknown -option */ SERVER_REC *cmd_options_get_server(const char *cmd, GHashTable *optlist, SERVER_REC *defserver) { SERVER_REC *server; GSList *list, *tmp, *next; /* get all the options, then remove the known ones. there should be only one left - the server tag. */ list = hashtable_get_keys(optlist); if (cmd != NULL) { for (tmp = list; tmp != NULL; tmp = next) { char *option = tmp->data; next = tmp->next; if (command_have_option(cmd, option)) list = g_slist_remove(list, option); } } if (list == NULL) return defserver; server = server_find_tag(list->data); if (server == NULL || list->next != NULL) { /* unknown option (not server tag) */ signal_emit("error command", 2, GINT_TO_POINTER(CMDERR_OPTION_UNKNOWN), server == NULL ? list->data : list->next->data); signal_stop(); server = NULL; } g_slist_free(list); return server; }
/* channel add <servertag> <channeltag> <name> */ bool cfg_conf_channel_add(struct cfg_state *cmd, char *args) { int fields = countfields(args); char stag[24], ctag[24], name[24]; struct server *srv; /* Add requires 3 variables */ if ( fields != 3 || !copyfield(args, 1, stag, sizeof(stag)) || !copyfield(args, 2, ctag, sizeof(ctag)) || !copyfield(args, 3, name, sizeof(name))) { sock_printf(cmd->sock, "400 The command is: channel add <servertag> <channeltag> <name>\n"); return false; } srv = server_find_tag(stag); if (!srv) { sock_printf(cmd->sock, "400 Server '%s' does not exist\n", stag); return false; } if (channel_find_tag(ctag)) { sock_printf(cmd->sock, "400 Channel '%s' does already exist\n", ctag); return false; } if (channel_add(srv, name, ctag)) { sock_printf(cmd->sock, "200 Added channel %s\n", ctag); return true; } sock_printf(cmd->sock, "400 Channel addition failed\n"); return false; }
/* * putchan_raw <server_tag> <#chan> <text> * Use this instead of putserv so that can see own message * * "raw" because putchan in Tcl will do some string fixing on text * * all command parameters should be using unicode (internal) encoding. */ int putchan_raw(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { (void) clientData; if (objc != 4) { Tcl_Obj* str = Tcl_ObjPrintf("wrong # args: should be \"putchan_raw" " server_tag channel text\""); Tcl_SetObjResult(interp, str); return TCL_ERROR; } Tcl_Obj* const server_tag = objv[1]; Tcl_Obj* const target = objv[2]; Tcl_Obj* const msg = objv[3]; // find the server in Irssi. SERVER_REC* server_rec = server_find_tag(Tcl_GetString(server_tag)); if (server_rec == NULL) { Tcl_Obj* str = Tcl_ObjPrintf("server with tag '%s' not found", Tcl_GetString(server_tag)); Tcl_SetObjResult(interp, str); return TCL_ERROR; } // find the channel on this server in Irssi. CHANNEL_REC* channel_rec = channel_find(server_rec, Tcl_GetString(target)); if (channel_rec == NULL) { Tcl_Obj* str = Tcl_ObjPrintf("channel '%s' not found on server '%s'", Tcl_GetString(target), Tcl_GetString(server_tag)); Tcl_SetObjResult(interp, str); return TCL_ERROR; } // create the full command string to send to the IRC server. // PRIVMSG <target> :<msg> // this is how we used to create the command but I am concerned it // is not dealing with encoding correctly. //Tcl_Obj* send_str = Tcl_ObjPrintf("PRIVMSG %s :%s", target, msg); // try to be more careful with how we build the string. // -1 means take everything up to first NULL. Tcl_Obj* send_str = Tcl_NewStringObj("PRIVMSG ", -1); if (!send_str) { return TCL_ERROR; } Tcl_AppendObjToObj(send_str, target); Tcl_AppendToObj(send_str, " :", strlen(" :")); Tcl_AppendObjToObj(send_str, msg); // send the command to the server. // from ByteArrObj docs: // "Obtaining the string representation of a byte-array object (by calling Tcl_GetStringFromObj) produces a properly formed UTF-8 sequence with a one-to-one mapping between the bytes in the internal representation and the UTF-8 characters in the string representation." irc_send_cmd((IRC_SERVER_REC*) server_rec, Tcl_GetString(send_str)); // this frees the object. unsure if I actually need to call this, but it // seems like it doesn't matter if I do! Tcl_DecrRefCount(send_str); // write the message to Irssi so we see it ourselves. print_message_public(server_rec, channel_rec, Tcl_GetString(target), server_rec->nick, NULL, Tcl_GetString(msg)); //signal_emit("message own_public", 3, server, text, chan); return TCL_OK; }
/* SYNTAX: RECONNECT <tag> [<quit message>] */ static void cmd_reconnect(const char *data, SERVER_REC *server) { SERVER_CONNECT_REC *conn; RECONNECT_REC *rec; char *tag, *msg; void *free_arg; int tagnum; if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &tag, &msg)) return; if (*tag != '\0' && strcmp(tag, "*") != 0) server = server_find_tag(tag); if (server != NULL) { /* reconnect connected server */ conn = server_connect_copy_skeleton(server->connrec, TRUE); if (server->connected) reconnect_save_status(conn, server); msg = g_strconcat("* ", *msg == '\0' ? "Reconnecting" : msg, NULL); signal_emit("command disconnect", 2, msg, server); g_free(msg); conn->reconnection = TRUE; server_connect(conn); server_connect_unref(conn); cmd_params_free(free_arg); return; } if (g_ascii_strcasecmp(tag, "all") == 0) { /* reconnect all servers in reconnect queue */ reconnect_all(); cmd_params_free(free_arg); return; } if (*data == '\0') { /* reconnect to first server in reconnection list */ if (reconnects == NULL) cmd_param_error(CMDERR_NOT_CONNECTED); rec = reconnects->data; } else { if (g_ascii_strncasecmp(data, "RECON-", 6) == 0) data += 6; tagnum = atoi(tag); rec = tagnum <= 0 ? NULL : reconnect_find_tag(tagnum); } if (rec == NULL) { signal_emit("server reconnect not found", 1, data); } else { conn = rec->conn; server_connect_ref(conn); server_reconnect_destroy(rec); server_connect(conn); server_connect_unref(conn); } cmd_params_free(free_arg); }
/* server set <servertag> <variable> <value> */ bool cfg_conf_server_set(struct cfg_state *cmd, char *args) { int fields = countfields(args); char tag[25], var[25], val[1000]; struct server *srv; struct channel *ch; /* Add requires 8 variables */ if ( fields != 3 || !copyfield(args, 1, tag, sizeof(tag)) || !copyfield(args, 2, var, sizeof(var)) || !copyfield(args, 3, val, sizeof(val))) { sock_printf(cmd->sock, "400 The command is: server set <servertag> <variable> <value>\n"); return false; } srv = server_find_tag(tag); if (!srv) { sock_printf(cmd->sock, "400 Server '%s' does not exist\n"); return false; } if (strcasecmp(var, "bitlbee_identifypass") == 0) { if (srv->bitlbee_identifypass) free(srv->bitlbee_identifypass); srv->bitlbee_identifypass = strdup(val); sock_printf(cmd->sock, "200 Configured the BitlBee password\n"); return true; } if (strcasecmp(var, "defaultchannel") == 0) { if ( srv->type != SRV_USER && srv->type != SRV_BITLBEE) { sock_printf(cmd->sock, "400 Defaultchannels are only required for user and BitlBee links\n", val); return false; } ch = channel_find_tag(val); if (!ch) { sock_printf(cmd->sock, "400 Channel '%s' does not exist\n", val); return false; } srv->defaultchannel = ch; /* Make sure that our user is also there */ channel_adduser(ch, srv->user); sock_printf(cmd->sock, "200 Configured the default channel\n"); return true; } sock_printf(cmd->sock, "400 Unknown settable value '%s'\n", var); return false; }
/* * Command: nicklist_getnicks <server tag> <channel> * * Retrieve the nicks in a channel. */ int tcl_command_nicklist_getnicks(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]) { (void) clientData; if (objc != 3) { Tcl_Obj* str = Tcl_ObjPrintf("wrong # args: should be \"nicklist_getnicks" " server_tag channel\""); Tcl_SetObjResult(interp, str); return TCL_ERROR; } Tcl_Obj* const server_tag = objv[1]; Tcl_Obj* const channel_name = objv[2]; // find the server. SERVER_REC* server_rec = server_find_tag(Tcl_GetString(server_tag)); if (!server_rec) { Tcl_Obj* str = Tcl_ObjPrintf("server with tag '%s' not found", Tcl_GetString(server_tag)); Tcl_SetObjResult(interp, str); return TCL_ERROR; } // find the channel on this server. CHANNEL_REC* channel_rec = channel_find(server_rec, Tcl_GetString(channel_name)); if (!channel_rec) { Tcl_Obj* str = Tcl_ObjPrintf("channel '%s' not found on server '%s'", Tcl_GetString(channel_name), Tcl_GetString(server_tag)); Tcl_SetObjResult(interp, str); return TCL_ERROR; } // get the nicks as a list. Tcl_Obj* list = Tcl_NewListObj(0, NULL); if (!list) { Tcl_Obj* str = Tcl_ObjPrintf("failed to create list"); Tcl_SetObjResult(interp, str); return TCL_ERROR; } GSList* nicks = nicklist_getnicks(channel_rec); for (GSList* nick_ptr = nicks; nick_ptr; nick_ptr = nick_ptr->next) { NICK_REC* nick = nick_ptr->data; // TODO: encoding issues? Tcl_Obj* nick_str = Tcl_NewStringObj(nick->nick, -1); if (!nick_str) { Tcl_Obj* str = Tcl_ObjPrintf("failed to create nick string"); Tcl_SetObjResult(interp, str); __tcl_command_free_tcl_list(interp, list); g_slist_free(nicks); return TCL_ERROR; } if (Tcl_ListObjAppendElement(interp, list, nick_str) != TCL_OK) { Tcl_Obj* str = Tcl_ObjPrintf("failed to append to list: '%s'", Tcl_GetString(nick_str)); Tcl_SetObjResult(interp, str); __tcl_command_free_tcl_list(interp, list); g_slist_free(nicks); return TCL_ERROR; } } g_slist_free(nicks); Tcl_SetObjResult(interp, list); return TCL_OK; }