#include "config.h" #include #include #include #include #include #include #include #include "proto.h" #include "seven_client.h" #include "panic.h" #include "x11.h" typedef int (*client_func_t)(const char **args); struct client_op { char *name; client_func_t func; const struct poptOption *options; char *desc; bool server_select; }; static char *dirname; int opt_all; static char *opt_server; static int opt_all_sevens; static int opt_force; static int sevens_found; static DIR *dirp; static const struct poptOption common_opts[] = { {NULL, 's', POPT_ARG_STRING, &opt_server, 0, "name of seven to find", "PID.TTY.MACHINE" }, {"all", 0, POPT_ARG_NONE, &opt_all_sevens, 0, "perform action on all sevens", NULL }, POPT_TABLEEND }; static const struct poptOption attach_options[] = { {NULL, 'F', POPT_ARG_NONE, &opt_force, 0, "force attachment, detaching first if necessary", NULL }, // {NULL, 0, POPT_ARG_INCLUDE_TABLE, (void *)common_opts, 0, "seven selection options", NULL }, // POPT_AUTOHELP POPT_TABLEEND }; static const struct poptOption ts_options[] = { {NULL, 'a', POPT_ARG_NONE, &opt_all, 0, "grab whole history, not just current screen", NULL }, // {NULL, 0, POPT_ARG_INCLUDE_TABLE, (void *)common_opts, 0, "seven selection options", NULL }, // POPT_AUTOHELP POPT_TABLEEND }; static CLIENT * find_client(DIR **dirp) { if(!*dirp) { if(!dirname) asprintf(&dirname, "/tmp/seven/%u", (unsigned)getuid()); *dirp = opendir(dirname); if(!*dirp) panicno(dirname); } struct dirent *de = NULL; while((de = readdir(*dirp))) { struct stat stat; char *buf; int ret = asprintf(&buf, "/tmp/seven/%u/%s", getuid(), de->d_name); if(ret == -1) panicno("asprintf"); if(lstat(buf, &stat) == -1) { free(buf); continue; } if(!S_ISSOCK(stat.st_mode)) { free(buf); continue; } CLIENT *clnt = clnt_create(buf, SEVENPROG, SEVENVERS, "unix"); free(buf); if(clnt) return clnt; } int ret = closedir(*dirp); if(ret == -1) panicno("closedir"); *dirp = NULL; return NULL; } static CLIENT * iter_clients(void) { CLIENT *c; while((c = find_client(&dirp))) { if(!opt_server && !opt_all_sevens && !sevens_found) { sevens_found++; return c; } if(opt_all_sevens) { sevens_found++; return c; } struct seven_info *si = sproto_getinfo_1(c); if(opt_server && strstr(si->name, opt_server)) { xdr_free((xdrproc_t)xdr_seven_info, (char *)si); sevens_found++; return c; } clnt_destroy(c); } return NULL; } static int client_switch_screen(const char **arg) { int nscreen; if(arg && *arg) nscreen = strtol(*arg, NULL, 0); else nscreen = -2; DIR *dir = NULL; CLIENT *c = find_client(&dir); if(!c) panic("no seven found."); sproto_switchscreen_1(nscreen, c); return 0; } static int client_ls(const char **args) { DIR *dir = NULL; CLIENT *clnt; int ret = 1; while((clnt = find_client(&dir))) { ret = 0; struct seven_info *si = sproto_getinfo_1(clnt); printf("%s\n", si->name); if(si->connections.connections_len) { printf(" WINDOWID=0x%x\n", si->connections.connections_val->xwindow); printf(" DISPLAY=%s\n", si->connections.connections_val->display ); printf(" XAUTHORITY=%s\n", si->connections.connections_val->xauthority ); printf(" SERVER_VENDOR=%s\n", si->connections.connections_val->server_vendor ); } else { puts(" (Disconnected)"); } printf(" TITLE=%s\n", si->title); printf(" CLASS=%s\n", si->klass); xdr_free((xdrproc_t)xdr_seven_info, (char *)si); clnt_destroy(clnt); } return ret; } static int client_ts(const char **args) { DIR *dir = NULL; CLIENT *c = find_client(&dir); if(!c) panic("no seven found."); closedir(dir); char **ts = sproto_textshot_1(opt_all, c); puts(*ts); return 0; } static int client_detach(const char **args) { CLIENT *c; while((c = iter_clients())) { sproto_detach_1(c); clnt_destroy(c); } return 0; } static int client_attach(const char **args) { CLIENT *c; struct x11_info x; x11_get_info(&x); while((c = iter_clients())) { if(opt_force) sproto_detach_1(c); sproto_attach_1(x,c); clnt_destroy(c); } return 0; } static int client_help(const char **args); static struct client_op cfuncs[] = { {"ls", client_ls, NULL, "List running sevens", false}, {"ts", client_ts, ts_options, "List running sevens", true}, {"ss", client_switch_screen, NULL, "Move seven to specified screen on same display", true }, {"detach", client_detach, NULL, "detach from X server if attached", true }, {"attach", client_attach, attach_options, "attach to current X server if detached", true }, {"help", client_help, NULL, "list client commands available (use --help for other options)", true } }; //struct poptOption include_commonopts = {NULL, 0, POPT_ARG_INCLUDE_TABLE, (void *)common_opts, 0, , NULL }; void do_client_call(int argc, const char **argv) { for(int i = 0; i < sizeof(cfuncs)/sizeof(struct client_op); i++) { if(!strcmp(argv[0], cfuncs[i].name)) { struct poptOption options[] = { {0,0,POPT_ARG_INCLUDE_TABLE, NULL, 0, NULL, NULL}, {0,0,POPT_ARG_INCLUDE_TABLE, NULL, 0, NULL, NULL}, POPT_AUTOHELP POPT_TABLEEND }; struct poptOption *opt = &options[2]; if(cfuncs[i].options) { opt--; opt->arg = (void *)cfuncs[i].options; opt->descrip = "Command Specific Options"; } if(cfuncs[i].server_select) { opt--; opt->arg = (void *)common_opts; opt->descrip = "seven selection options"; } poptContext popt = poptGetContext(PACKAGE, argc, argv, opt, 0); int rc = poptGetNextOpt(popt); if (rc < -1) { /* an error occurred during option processing */ fprintf(stderr, "%s: %s\n", poptBadOption(popt, POPT_BADOPTION_NOALIAS), poptStrerror(rc)); exit(1); } const char **args = poptGetArgs(popt); exit(cfuncs[i].func(args)); } } fprintf(stderr, "Unknown client command: %s\n", argv[0]); exit(1); //poptFreeContext(popt); } static int client_help(const char **args) { for(int i = 0; i < sizeof(cfuncs)/sizeof(struct client_op); i++) { printf("%6.6s - %s\n",cfuncs[i].name, cfuncs[i].desc); } return 0; }