static void c_msg(char *args) { char *sep = strchr(args, ' '); if(sep) { *sep = 0; while(*(++sep) == ' '); } struct ui_tab *tab = ui_tab_cur->data; if(tab->type != UIT_HUB && tab->type != UIT_MSG) ui_m(NULL, 0, "This command can only be used on hub and message tabs."); else if(!tab->hub->nick_valid) ui_m(NULL, 0, "Not connected or logged in yet."); else if(!args[0]) ui_m(NULL, 0, "No user specified. See `/help msg' for more information."); else { struct hub_user *u = hub_user_get(tab->hub, args); if(!u) ui_m(NULL, 0, "No user found with that name. Note that usernames are case-sensitive."); else { // get or open tab and make sure it's selected struct ui_tab *t = g_hash_table_lookup(ui_msg_tabs, &u->uid); if(!t) ui_tab_open(ui_msg_create(tab->hub, u), TRUE, tab); else ui_tab_cur = g_list_find(ui_tabs, t); // if we need to send something, do so if(sep && *sep) hub_msg(tab->hub, u, sep, FALSE, 0); } } }
static gboolean c_connect_set_hubaddr(char *addr) { // Validate and parse GRegex *reg = g_regex_new( // 1 - proto 2 - host 3 - port 4 - kp "^(?:(dchub|nmdcs?|adcs?)://)?([^ :/<>\\(\\)]+)(?::([0-9]+))?(?:/|/\\?kp=SHA256\\/([a-zA-Z2-7]{52}))?$", 0, 0, NULL); g_assert(reg); GMatchInfo *nfo; if(!g_regex_match(reg, addr, 0, &nfo)) { ui_m(NULL, 0, "Invalid URL format."); // not very specific g_regex_unref(reg); return FALSE; } g_regex_unref(reg); char *proto = g_match_info_fetch(nfo, 1); char *kp = g_match_info_fetch(nfo, 4); if(kp && *kp && strcmp(proto, "adcs") != 0 && strcmp(proto, "nmdcs") != 0) { ui_m(NULL, 0, "Keyprint is only valid for adcs:// or nmdcs:// URLs."); g_match_info_free(nfo); g_free(proto); g_free(kp); return FALSE; } char *host = g_match_info_fetch(nfo, 2); char *port = g_match_info_fetch(nfo, 3); g_match_info_free(nfo); struct ui_tab *tab = ui_tab_cur->data; char *old = g_strdup(var_get(tab->hub->id, VAR_hubaddr)); // Reconstruct (without the kp) and save GString *a = g_string_new(""); g_string_printf(a, "%s://%s:%s/", !proto || !*proto ? "dchub" : proto, host, !port || !*port ? "411" : port); var_set(tab->hub->id, VAR_hubaddr, a->str, NULL); // Save kp if specified, or throw it away if the URL changed if(kp && *kp) var_set(tab->hub->id, VAR_hubkp, kp, NULL); else if(old && strcmp(old, a->str) != 0) var_set(tab->hub->id, VAR_hubkp, NULL, NULL); g_string_free(a, TRUE); g_free(old); g_free(proto); g_free(kp); g_free(host); g_free(port); return TRUE; }
static void c_connect(char *args) { struct ui_tab *tab = ui_tab_cur->data; if(tab->type != UIT_HUB) ui_m(NULL, 0, "This command can only be used on hub tabs."); else if(tab->hub->net->connecting || tab->hub->net->conn) ui_m(NULL, 0, "Already connected (or connecting). You may want to /disconnect first."); else { if(args[0] && !c_connect_set_hubaddr(args)) ; else if(!var_get(tab->hub->id, VAR_hubaddr)) ui_m(NULL, 0, "No hub address configured. Use '/connect <address>' to do so."); else hub_connect(tab->hub); } }
// handle /say and /me static void sayme(char *args, gboolean me) { struct ui_tab *tab = ui_tab_cur->data; if(tab->type != UIT_HUB && tab->type != UIT_MSG) ui_m(NULL, 0, "This command can only be used on hub and message tabs."); else if(!tab->hub->nick_valid) ui_m(NULL, 0, "Not connected or logged in yet."); else if(!args[0]) ui_m(NULL, 0, "Message empty."); else if(tab->type == UIT_HUB) hub_say(tab->hub, args, me); else { struct hub_user *u = g_hash_table_lookup(hub_uids, &tab->uid); if(!u) ui_m(NULL, 0, "User is not online."); else hub_msg(tab->hub, u, args, me, tab->msg_replyto); } }
static void c_accept(char *args) { struct ui_tab *tab = ui_tab_cur->data; if(args[0]) ui_m(NULL, 0, "This command does not accept any arguments."); else if(tab->type != UIT_HUB) ui_m(NULL, 0, "This command can only be used on hub tabs."); #if TLS_SUPPORT else if(!tab->hub->kp) ui_m(NULL, 0, "Nothing to accept."); else { char enc[53] = {}; base32_encode_dat(tab->hub->kp, enc, 32); var_set(tab->hub->id, VAR_hubkp, enc, NULL); g_slice_free1(32, tab->hub->kp); tab->hub->kp = NULL; hub_connect(tab->hub); } #else else
static void c_disconnect(char *args) { struct ui_tab *tab = ui_tab_cur->data; if(args[0]) ui_m(NULL, 0, "This command does not accept any arguments."); else if(tab->type == UIT_HUB) { if(!tab->hub->net->conn && !tab->hub->reconnect_timer && !tab->hub->net->connecting) ui_m(NULL, 0, "Not connected."); else hub_disconnect(tab->hub, FALSE); } else if(tab->type == UIT_MAIN) { ui_m(NULL, 0, "Disconnecting all hubs."); GList *n = ui_tabs; for(; n; n=n->next) { tab = n->data; if(tab->type == UIT_HUB && (tab->hub->net->conn || tab->hub->net->connecting || tab->hub->reconnect_timer)) hub_disconnect(tab->hub, FALSE); } } else ui_m(NULL, 0, "This command can only be used on the main tab or on hub tabs."); }
static void c_reconnect(char *args) { struct ui_tab *tab = ui_tab_cur->data; if(args[0]) ui_m(NULL, 0, "This command does not accept any arguments."); else if(tab->type == UIT_HUB) { if(tab->hub->net->conn || tab->hub->net->connecting || tab->hub->reconnect_timer) hub_disconnect(tab->hub, FALSE); c_connect(""); // also checks for the existence of "hubaddr" } else if(tab->type == UIT_MAIN) { ui_m(NULL, 0, "Reconnecting all hubs."); GList *n = ui_tabs; for(; n; n=n->next) { tab = n->data; if(tab->type != UIT_HUB) continue; if(tab->hub->net->conn || tab->hub->net->connecting || tab->hub->reconnect_timer) hub_disconnect(tab->hub, FALSE); ui_tab_cur = n; c_connect(""); } ui_tab_cur = g_list_find(ui_tabs, ui_main); } else ui_m(NULL, 0, "This command can only be used on the main tab or on hub tabs."); }
static char *p_nick(const char *val, GError **err) { if(strlen(val) > 32) { g_set_error_literal(err, 1, 0, "Too long nick name."); return NULL; } if(strlen(val) < 1) { g_set_error_literal(err, 1, 0, "Too short nick name."); return NULL; } int i; for(i=strlen(val)-1; i>=0; i--) if(val[i] == '$' || val[i] == '|' || val[i] == ' ' || val[i] == '<' || val[i] == '>') break; if(i >= 0) { g_set_error_literal(err, 1, 0, "Invalid character in nick name."); return NULL; } ui_m(NULL, 0, "Your new nick will be used for new hub connections."); return g_strdup(val); }
static gboolean s_dl_inc_dir(guint64 hub, const char *key, const char *val, GError **err) { gboolean dl = strcmp(key, "download_dir") == 0 ? TRUE : FALSE; // Don't allow changes to incoming_dir when the download queue isn't empty if(!dl && g_hash_table_size(dl_queue) > 0) { g_set_error_literal(err, 1, 0, "Can't change the incoming directory unless the download queue is empty."); return FALSE; } char *tmp = val ? g_strdup(val) : i_dl_inc_dir(dl); char nval[strlen(tmp)+1]; strcpy(nval, tmp); g_free(tmp); // make sure it exists if(g_mkdir_with_parents(nval, 0777)) { g_set_error(err, 1, 0, "Error creating the directory: %s", g_strerror(errno)); return FALSE; } // test whether they are on the same filesystem struct stat a, b; char *bd = var_get(0, dl ? VAR_incoming_dir : VAR_download_dir); if(stat(bd, &b) < 0) { g_set_error(err, 1, 0, "Error stat'ing %s: %s", bd, g_strerror(errno)); return FALSE; } if(stat(nval, &a) < 0) { g_set_error(err, 1, 0, "Error stat'ing %s: %s", nval, g_strerror(errno)); return FALSE; } if(a.st_dev != b.st_dev) ui_m(NULL, 0, "WARNING: The download directory is not on the same filesystem as the incoming" " directory. This may cause the program to hang when downloading large files."); db_vars_set(hub, key, val); return TRUE; }
static void c_help(char *args) { char *sec = strchr(args, ' '); if(sec) *(sec++) = 0; // list available commands if(!args[0]) { ui_m(NULL, 0, "\nAvailable commands:"); struct cmd *c = cmds; for(; c->f; c++) ui_mf(NULL, 0, " /%s - %s", c->name, getdoc(c)->sum); ui_m(NULL, 0, "\nFor help on key bindings, use `/help keys'.\n"); // list information on a setting } else if((strcmp(args, "set") == 0 || strcmp(args, "hset") == 0) && sec) { sec = strncmp(sec, "color_", 6) == 0 ? "color_*" : sec; struct doc_set *s = (struct doc_set *)doc_sets; for(; s->name; s++) if(strcmp(s->name, sec) == 0) break; if(!s->name) ui_mf(NULL, 0, "\nUnknown setting '%s'.", sec); else ui_mf(NULL, 0, "\nSetting: %s.%s %s\n\n%s\n", s->hub ? "#hub" : "global", s->name, s->type, s->desc); // list available key sections } else if(strcmp(args, "keys") == 0 && !sec) { ui_m(NULL, 0, "\nAvailable sections:"); const struct doc_key *k = doc_keys; for(; k->sect; k++) ui_mf(NULL, 0, " %s - %s", k->sect, k->title); ui_m(NULL, 0, "\nUse `/help keys <name>' to get help on the key bindings for the selected section.\n"); // get information on a particular key section } else if(strcmp(args, "keys") == 0 && sec) { const struct doc_key *k = doc_keys; for(; k->sect; k++) if(strcmp(k->sect, sec) == 0) break; if(!k->sect) ui_mf(NULL, 0, "\nUnknown keys section '%s'.", sec); else ui_mf(NULL, 0, "\nKey bindings for: %s - %s.\n\n%s\n", k->sect, k->title, k->desc); // get information on a particular command } else if(!sec) { if(*args == '/') args++; struct cmd *c = getcmd(args); if(!c) ui_mf(NULL, 0, "\nUnknown command '%s'.", args); else { struct doc_cmd *d = getdoc(c); ui_mf(NULL, 0, "\nUsage: /%s %s\n %s\n", c->name, d->args ? d->args : "", d->sum); if(d->desc) ui_mf(NULL, 0, "%s\n", d->desc); } } else ui_mf(NULL, 0, "\nUnknown help section `%s'.", args); }
static void t_key(ui_tab_t *tab, guint64 key) { tab_t *t = (tab_t *)tab; if(ui_listing_key(t->list, key, winrows/2)) return; hub_user_t *sel = g_sequence_iter_is_end(t->list->sel) ? NULL : g_sequence_get(t->list->sel); gboolean sort = FALSE; switch(key) { case INPT_CHAR('?'): uit_main_keys("userlist"); break; // Sorting #define SETSORT(c) \ t->reverse = t->order == c ? !t->reverse : FALSE;\ t->order = c;\ sort = TRUE; case INPT_CHAR('s'): // s/S - sort on share size case INPT_CHAR('S'): SETSORT(SORT_SHARE); break; case INPT_CHAR('u'): // u/U - sort on username case INPT_CHAR('U'): SETSORT(SORT_USER) break; case INPT_CHAR('D'): // D - sort on description SETSORT(SORT_DESC) break; case INPT_CHAR('T'): // T - sort on client (= tag) SETSORT(SORT_CLIENT) break; case INPT_CHAR('E'): // E - sort on email SETSORT(SORT_MAIL) break; case INPT_CHAR('C'): // C - sort on connection SETSORT(SORT_CONN) break; case INPT_CHAR('P'): // P - sort on IP SETSORT(SORT_IP) break; case INPT_CHAR('o'): // o - toggle sorting OPs before others t->opfirst = !t->opfirst; sort = TRUE; break; #undef SETSORT // Column visibility case INPT_CHAR('d'): // d (toggle description visibility) t->hide_desc = !t->hide_desc; break; case INPT_CHAR('t'): // t (toggle tag visibility) t->hide_tag = !t->hide_tag; break; case INPT_CHAR('e'): // e (toggle e-mail visibility) t->hide_mail = !t->hide_mail; break; case INPT_CHAR('c'): // c (toggle connection visibility) t->hide_conn = !t->hide_conn; break; case INPT_CHAR('p'): // p (toggle IP visibility) t->hide_ip = !t->hide_ip; break; case INPT_CTRL('j'): // newline case INPT_CHAR('i'): // i (toggle user info) t->details = !t->details; break; case INPT_CHAR('m'): // m (/msg user) if(!sel) ui_m(NULL, 0, "No user selected."); else uit_msg_open(sel->uid, tab); break; case INPT_CHAR('g'): // g (grant slot) if(!sel) ui_m(NULL, 0, "No user selected."); else { db_users_set(sel->hub->id, sel->uid, sel->name, db_users_get(sel->hub->id, sel->name) | DB_USERFLAG_GRANT); ui_m(NULL, 0, "Slot granted."); } break; case INPT_CHAR('b'): // b (/browse userlist) case INPT_CHAR('B'): // B (force /browse userlist) if(!sel) ui_m(NULL, 0, "No user selected."); else uit_fl_queue(sel->uid, key == INPT_CHAR('B'), NULL, tab, TRUE, FALSE); break; case INPT_CHAR('q'): // q - download filelist and match queue for selected user if(!sel) ui_m(NULL, 0, "No user selected."); else uit_fl_queue(sel->uid, FALSE, NULL, NULL, FALSE, TRUE); break; } if(sort) { g_sequence_sort(t->list->list, sort_func, tab); ui_listing_sorted(t->list); ui_mf(NULL, 0, "Ordering by %s (%s%s)", t->order == SORT_USER ? "user name" : t->order == SORT_SHARE ? "share size" : t->order == SORT_CONN ? "connection" : t->order == SORT_DESC ? "description" : t->order == SORT_MAIL ? "e-mail" : t->order == SORT_CLIENT? "tag" : "IP address", t->reverse ? "descending" : "ascending", t->opfirst ? ", OPs first" : ""); } }