]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libplumb/mesg.c
mothra: fix alt display resizing, filter control characters in panel entries, use...
[plan9front.git] / sys / src / libplumb / mesg.c
1 #include <u.h>
2 #include <libc.h>
3 #include "plumb.h"
4
5 static char attrbuf[4096];
6
7 int
8 plumbopen(char *name, int omode)
9 {
10         int fd, f;
11         char *s, *plumber;
12         char buf[128], err[ERRMAX];
13
14         if(name[0] == '/')
15                 return open(name, omode);
16                 
17         /* find elusive plumber */
18         if(access("/mnt/plumb/send", AWRITE) >= 0)
19                 plumber = "/mnt/plumb";
20         else if(access("/mnt/term/mnt/plumb/send", AWRITE) >= 0)
21                 plumber = "/mnt/term/mnt/plumb";
22         else{
23                 /* last resort: try mounting service */
24                 plumber = "/mnt/plumb";
25                 s = getenv("plumbsrv");
26                 if(s == nil)
27                         return -1;
28                 f = open(s, ORDWR);
29                 free(s);
30                 if(f < 0)
31                         return -1;
32                 if(mount(f, -1, "/mnt/plumb", MREPL, "") < 0){
33                         close(f);
34                         return -1;
35                 }
36                 if(access("/mnt/plumb/send", AWRITE) < 0)
37                         return -1;
38         }
39
40         snprint(buf, sizeof buf, "%s/%s", plumber, name);
41         fd = open(buf, omode);
42         if(fd >= 0)
43                 return fd;
44
45         /* try creating port; used by non-standard plumb implementations */
46         rerrstr(err, sizeof err);
47         fd = create(buf, omode, 0600);
48         if(fd >= 0)
49                 return fd;
50         errstr(err, sizeof err);
51
52         return -1;
53 }
54
55 static int
56 Strlen(char *s)
57 {
58         if(s == nil)
59                 return 0;
60         return strlen(s);
61 }
62
63 static char*
64 Strcpy(char *s, char *t)
65 {
66         if(t == nil)
67                 return s;
68         return strcpy(s, t) + strlen(t);
69 }
70
71 /* quote attribute value, if necessary */
72 static char*
73 quote(char *s)
74 {
75         char *t;
76         int c;
77
78         if(s == nil){
79                 attrbuf[0] = '\0';
80                 return attrbuf;
81         }
82         if(strpbrk(s, " '=\t") == nil)
83                 return s;
84         t = attrbuf;
85         *t++ = '\'';
86         while(t < attrbuf+sizeof attrbuf-2){
87                 c = *s++;
88                 if(c == '\0')
89                         break;
90                 *t++ = c;
91                 if(c == '\'')
92                         *t++ = c;
93         }
94         *t++ = '\'';
95         *t = '\0';
96         return attrbuf;
97 }
98
99 char*
100 plumbpackattr(Plumbattr *attr)
101 {
102         int n;
103         Plumbattr *a;
104         char *s, *t;
105
106         if(attr == nil)
107                 return nil;
108         n = 0;
109         for(a=attr; a!=nil; a=a->next)
110                 n += Strlen(a->name) + 1 + Strlen(quote(a->value)) + 1;
111         s = malloc(n);
112         if(s == nil)
113                 return nil;
114         t = s;
115         *t = '\0';
116         for(a=attr; a!=nil; a=a->next){
117                 if(t != s)
118                         *t++ = ' ';
119                 strcpy(t, a->name);
120                 strcat(t, "=");
121                 strcat(t, quote(a->value));
122                 t += strlen(t);
123         }
124         if(t > s+n)
125                 abort();
126         return s;
127 }
128
129 char*
130 plumblookup(Plumbattr *attr, char *name)
131 {
132         while(attr){
133                 if(strcmp(attr->name, name) == 0)
134                         return attr->value;
135                 attr = attr->next;
136         }
137         return nil;
138 }
139
140 char*
141 plumbpack(Plumbmsg *m, int *np)
142 {
143         int n, ndata;
144         char *buf, *p, *attr;
145
146         ndata = m->ndata;
147         if(ndata < 0)
148                 ndata = Strlen(m->data);
149         attr = plumbpackattr(m->attr);
150         n = Strlen(m->src)+1 + Strlen(m->dst)+1 + Strlen(m->wdir)+1 +
151                 Strlen(m->type)+1 + Strlen(attr)+1 + 16 + ndata;
152         buf = malloc(n+1);      /* +1 for '\0' */
153         if(buf == nil){
154                 free(attr);
155                 return nil;
156         }
157         p = Strcpy(buf, m->src);
158         *p++ = '\n';
159         p = Strcpy(p, m->dst);
160         *p++ = '\n';
161         p = Strcpy(p, m->wdir);
162         *p++ = '\n';
163         p = Strcpy(p, m->type);
164         *p++ = '\n';
165         p = Strcpy(p, attr);
166         *p++ = '\n';
167         p += sprint(p, "%d\n", ndata);
168         memmove(p, m->data, ndata);
169         *np = (p-buf)+ndata;
170         buf[*np] = '\0';        /* null terminate just in case */
171         if(*np >= n+1)
172                 abort();
173         free(attr);
174         return buf;
175 }
176
177 int
178 plumbsend(int fd, Plumbmsg *m)
179 {
180         char *buf;
181         int n;
182
183         buf = plumbpack(m, &n);
184         if(buf == nil)
185                 return -1;
186         n = write(fd, buf, n);
187         free(buf);
188         return n;
189 }
190
191 static int
192 plumbline(char **linep, char *buf, int i, int n, int *bad)
193 {
194         int starti;
195         char *p;
196
197         starti = i;
198         while(i<n && buf[i]!='\n')
199                 i++;
200         if(i == n)
201                 *bad = 1;
202         else{
203                 p = malloc((i-starti) + 1);
204                 if(p == nil)
205                         *bad = 1;
206                 else{
207                         memmove(p, buf+starti, i-starti);
208                         p[i-starti] = '\0';
209                 }
210                 *linep = p;
211                 i++;
212         }
213         return i;
214 }
215
216 void
217 plumbfree(Plumbmsg *m)
218 {
219         Plumbattr *a, *next;
220
221         free(m->src);
222         free(m->dst);
223         free(m->wdir);
224         free(m->type);
225         for(a=m->attr; a!=nil; a=next){
226                 next = a->next;
227                 free(a->name);
228                 free(a->value);
229                 free(a);
230         }
231         free(m->data);
232         free(m);
233 }
234
235 Plumbattr*
236 plumbunpackattr(char *p)
237 {
238         Plumbattr *attr, *prev, *a;
239         char *q, *v;
240         int c, quoting;
241
242         attr = prev = nil;
243         while(*p!='\0' && *p!='\n'){
244                 while(*p==' ' || *p=='\t')
245                         p++;
246                 if(*p == '\0')
247                         break;
248                 for(q=p; *q!='\0' && *q!='\n' && *q!=' ' && *q!='\t'; q++)
249                         if(*q == '=')
250                                 break;
251                 if(*q != '=')
252                         break;  /* malformed attribute */
253                 a = malloc(sizeof(Plumbattr));
254                 if(a == nil)
255                         break;
256                 a->name = malloc(q-p+1);
257                 if(a->name == nil){
258                         free(a);
259                         break;
260                 }
261                 memmove(a->name, p, q-p);
262                 a->name[q-p] = '\0';
263                 /* process quotes in value */
264                 q++;    /* skip '=' */
265                 v = attrbuf;
266                 quoting = 0;
267                 while(*q!='\0' && *q!='\n'){
268                         if(v >= attrbuf+sizeof attrbuf)
269                                 break;
270                         c = *q++;
271                         if(quoting){
272                                 if(c == '\''){
273                                         if(*q == '\'')
274                                                 q++;
275                                         else{
276                                                 quoting = 0;
277                                                 continue;
278                                         }
279                                 }
280                         }else{
281                                 if(c==' ' || c=='\t')
282                                         break;
283                                 if(c == '\''){
284                                         quoting = 1;
285                                         continue;
286                                 }
287                         }
288                         *v++ = c;
289                 }
290                 a->value = malloc(v-attrbuf+1);
291                 if(a->value == nil){
292                         free(a->name);
293                         free(a);
294                         break;
295                 }
296                 memmove(a->value, attrbuf, v-attrbuf);
297                 a->value[v-attrbuf] = '\0';
298                 a->next = nil;
299                 if(prev == nil)
300                         attr = a;
301                 else
302                         prev->next = a;
303                 prev = a;
304                 p = q;
305         }
306         return attr;
307 }
308
309 Plumbattr*
310 plumbaddattr(Plumbattr *attr, Plumbattr *new)
311 {
312         Plumbattr *l;
313
314         l = attr;
315         if(l == nil)
316                 return new;
317         while(l->next != nil)
318                 l = l->next;
319         l->next = new;
320         return attr;
321 }
322
323 Plumbattr*
324 plumbdelattr(Plumbattr *attr, char *name)
325 {
326         Plumbattr *l, *prev;
327
328         prev = nil;
329         for(l=attr; l!=nil; l=l->next){
330                 if(strcmp(name, l->name) == 0)
331                         break;
332                 prev = l;
333         }
334         if(l == nil)
335                 return nil;
336         if(prev)
337                 prev->next = l->next;
338         else
339                 attr = l->next;
340         free(l->name);
341         free(l->value);
342         free(l);
343         return attr;
344 }
345
346 Plumbmsg*
347 plumbunpackpartial(char *buf, int n, int *morep)
348 {
349         Plumbmsg *m;
350         int i, bad;
351         char *ntext, *attr;
352
353         m = malloc(sizeof(Plumbmsg));
354         if(m == nil)
355                 return nil;
356         memset(m, 0, sizeof(Plumbmsg));
357         if(morep != nil)
358                 *morep = 0;
359         bad = 0;
360         i = plumbline(&m->src, buf, 0, n, &bad);
361         i = plumbline(&m->dst, buf, i, n, &bad);
362         i = plumbline(&m->wdir, buf, i, n, &bad);
363         i = plumbline(&m->type, buf, i, n, &bad);
364         i = plumbline(&attr, buf, i, n, &bad);
365         i = plumbline(&ntext, buf, i, n, &bad);
366         if(bad){
367                 plumbfree(m);
368                 return nil;
369         }
370         m->attr = plumbunpackattr(attr);
371         free(attr);
372         m->ndata = atoi(ntext);
373         if(m->ndata != n-i){
374                 bad = 1;
375                 if(morep!=nil && m->ndata>n-i)
376                         *morep = m->ndata - (n-i);
377         }
378         free(ntext);
379         if(!bad){
380                 m->data = malloc(n-i+1);        /* +1 for '\0' */
381                 if(m->data == nil)
382                         bad = 1;
383                 else{
384                         memmove(m->data, buf+i, m->ndata);
385                         m->ndata = n-i;
386                         /* null-terminate in case it's text */
387                         m->data[m->ndata] = '\0';
388                 }
389         }
390         if(bad){
391                 plumbfree(m);
392                 m = nil;
393         }
394         return m;
395 }
396
397 Plumbmsg*
398 plumbunpack(char *buf, int n)
399 {
400         return plumbunpackpartial(buf, n, nil);
401 }
402
403 Plumbmsg*
404 plumbrecv(int fd)
405 {
406         char *buf;
407         Plumbmsg *m;
408         int n, more;
409
410         buf = malloc(8192);
411         if(buf == nil)
412                 return nil;
413         n = read(fd, buf, 8192);
414         m = nil;
415         if(n > 0){
416                 m = plumbunpackpartial(buf, n, &more);
417                 if(m==nil && more>0){
418                         /* we now know how many more bytes to read for complete message */
419                         buf = realloc(buf, n+more);
420                         if(buf == nil)
421                                 return nil;
422                         if(readn(fd, buf+n, more) == more)
423                                 m = plumbunpackpartial(buf, n+more, nil);
424                 }
425         }
426         free(buf);
427         return m;
428 }