Added interactive distinction to dsch.
[doldaconnect.git] / clients / tty / dcsh.c
CommitLineData
a24f31ec 1/*
2 * Dolda Connect - Modular multiuser Direct Connect-style client
302a2600 3 * Copyright (C) 2007 Fredrik Tolf <fredrik@dolda2000.com>
a24f31ec 4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18*/
19
20#include <stdlib.h>
21#include <stdio.h>
22#include <unistd.h>
23#include <wchar.h>
24#include <sys/poll.h>
c8817ca2 25#include <string.h>
15ee5bfb 26#include <errno.h>
c8817ca2 27#include <locale.h>
a24f31ec 28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include <doldaconnect/uilib.h>
33#include <doldaconnect/uimisc.h>
34#include <doldaconnect/utils.h>
35
fa51e153 36int interactive = 0;
a24f31ec 37int verbose = 0;
38int dcfd;
39
c8817ca2
FT
40struct cmd {
41 wchar_t *name;
42 int (*handler)(int argc, wchar_t **argv);
43};
44
fa51e153
FT
45void wcslimit(wchar_t *wcs, int limit) {
46 int i;
47
48 if(wcslen(wcs) > limit) {
49 for(i = limit - 3; i < limit; i++)
50 wcs[i] = L'.';
51 wcs[i] = L'\0';
52 }
53}
54
c8817ca2
FT
55int cmd_lsnodes(int argc, wchar_t **argv)
56{
c8817ca2
FT
57 struct dc_response *resp;
58 struct dc_intresp *ires;
59
60 resp = dc_gettaggedrespsync(dc_queuecmd(NULL, NULL, L"lsnodes", NULL));
61 if(resp->code == 200) {
fa51e153
FT
62 if(interactive) {
63 printf(" ID NET USERS S NAME\n");
64 printf("----- ---- ------ - ----------------------------------------------------------\n");
65 }
c8817ca2 66 while((ires = dc_interpret(resp)) != NULL) {
fa51e153
FT
67 if(interactive)
68 wcslimit(ires->argv[2].val.str, 58);
c8817ca2
FT
69 printf("%5i %4ls %6i %c %ls\n", ires->argv[0].val.num, ires->argv[1].val.str, ires->argv[3].val.num, "SHED"[ires->argv[4].val.num], ires->argv[2].val.str);
70 dc_freeires(ires);
71 }
72 } else if(resp->code == 201) {
73 } else {
74 fprintf(stderr, "dcsh: %ls\n", resp->rlines[0].argv[0]);
75 }
76 return(0);
77}
78
79struct cmd commands[] = {
80 {L"hubs", cmd_lsnodes},
81 {NULL, NULL}
82};
83
84int run1(int argc, wchar_t **argv)
85{
86 struct cmd *c;
87
88 for(c = commands; c->handler != NULL; c++) {
89 if(!wcscmp(argv[0], c->name))
90 return(c->handler(argc, argv));
91 }
92 fprintf(stderr, "dcsh: no such command\n");
93 return(1);
94}
95
96int runchar(int argc, char **argv) {
97 int i, rv;
98 wchar_t **wargv, *buf;
99 size_t wargvsize, wargvdata;
100
101 wargv = NULL;
102 wargvsize = wargvdata = 0;
103 for(i = 0; i < argc; i++) {
104 if((buf = icmbstowcs(argv[i], NULL)) == NULL) {
105 fprintf(stderr, "dcsh: could not convert %s to wide char: %s\n", argv[i], strerror(errno));
106 for(i = 0; i < wargvdata; i++)
107 free(wargv[i]);
108 if(wargv != NULL)
109 free(wargv);
110 return(1);
111 }
112 addtobuf(wargv, buf);
113 }
114 addtobuf(wargv, NULL);
115 rv = run1(wargvdata - 1, wargv);
116 dc_freewcsarr(wargv);
117 return(rv);
118}
119
120int shell(void)
121{
122 int ret, argc;
123 wchar_t *buf, **argv;
124 char *p, cmdbuf[128];
125 int cmddata;
126 struct pollfd pfd[2];
127
fa51e153
FT
128 if(interactive) {
129 fprintf(stderr, "dcsh> ");
130 fflush(stderr);
131 }
c8817ca2
FT
132 cmddata = 0;
133 while(1) {
134 pfd[0].fd = dcfd;
135 pfd[0].events = POLLIN;
136 if(dc_wantwrite())
137 pfd[0].events |= POLLOUT;
138 pfd[1].fd = 0;
139 pfd[1].events = POLLIN;
140 pfd[1].revents = 0;
141 if(poll(pfd, 2, -1) < 0) {
142 if(errno != EINTR) {
143 perror("dcsh: poll");
144 exit(1);
145 }
146 }
147 if(((pfd[0].revents & POLLIN) && dc_handleread()) || ((pfd[0].revents & POLLOUT) && dc_handlewrite()))
148 return(1);
149 if(pfd[1].revents) {
150 ret = read(0, cmdbuf + cmddata, sizeof(cmdbuf) - cmddata);
151 if(ret < 0) {
152 fprintf(stderr, "dcsh: stdin: %s\n", strerror(errno));
153 return(1);
154 } else if(ret == 0) {
fa51e153
FT
155 if(interactive)
156 fprintf(stderr, "\n");
c8817ca2
FT
157 return(0);
158 }
159 cmddata += ret;
160 while((p = memchr(cmdbuf, '\n', cmddata)) != NULL) {
161 *(p++) = 0;
162 if((buf = icmbstowcs(cmdbuf, NULL)) == NULL) {
163 fprintf(stderr, "dcsh: could not convert command to wide chars: %s\n", strerror(errno));
164 } else {
165 argv = dc_lexsexpr(buf);
166 free(buf);
167 for(argc = 0; argv[argc] != NULL; argc++);
168 if(argc > 0)
169 run1(argc, argv);
170 dc_freewcsarr(argv);
171 }
172 memmove(cmdbuf, p, cmddata -= (p - cmdbuf));
fa51e153
FT
173 if(interactive) {
174 fprintf(stderr, "dcsh> ");
175 fflush(stderr);
176 }
c8817ca2
FT
177 }
178 }
179 }
180}
181
a24f31ec 182int main(int argc, char **argv)
183{
c8817ca2 184 int c, rv;
a24f31ec 185 char *server;
186 char *username;
187 int authless, authia;
a24f31ec 188
c8817ca2 189 setlocale(LC_ALL, "");
a24f31ec 190 server = username = NULL;
191 authless = authia = 1;
192 while((c = getopt(argc, argv, "hvIAs:u:")) != -1) {
193 switch(c) {
194 case 's':
195 server = optarg;
196 break;
197 case 'u':
198 username = optarg;
199 break;
200 case 'I':
201 authia = 0;
202 break;
203 case 'A':
204 authless = 0;
205 break;
206 case 'v':
207 verbose++;
208 break;
209 default:
c8817ca2 210 fprintf(stderr, "usage: dcsh [-AIhv] [-s SERVER] [-u USERNAME] [COMMAND [ARGS...]]\n");
a24f31ec 211 exit((c == 'h')?0:1);
212 }
213 }
214 dc_init();
215
216 if(verbose)
217 fprintf(stderr, "connecting...\n");
218 if((dcfd = dc_connectsync2(server, 1)) < 0) {
219 perror("dcsh: could not connect to server");
220 exit(1);
221 }
222 if(verbose)
223 fprintf(stderr, "authenticating...\n");
224 if(dc_login(username, authless, authia?dc_convtty:dc_convnone, NULL) != DC_LOGIN_ERR_SUCCESS) {
225 fprintf(stderr, "dcsh: authentication unsuccessful\n");
226 exit(1);
227 }
228 if(verbose)
229 fprintf(stderr, "done\n");
fa51e153
FT
230 if(optind < argc) {
231 interactive = isatty(1);
c8817ca2 232 rv = runchar(argc - optind, argv + optind);
fa51e153
FT
233 } else {
234 interactive = isatty(0);
c8817ca2 235 rv = shell();
fa51e153 236 }
c8817ca2 237 return(rv);
a24f31ec 238}