Fix long-standing problem with getans(); handle the case if we get
[mmh] / sbr / client.c
1
2 /*
3  * client.c -- connect to a server
4  *
5  * This code is Copyright (c) 2002, by the authors of nmh.  See the
6  * COPYRIGHT file in the root directory of the nmh distribution for
7  * complete copyright information.
8  */
9
10 #include <h/mh.h>
11 #include <h/mts.h>
12 #include <h/utils.h>
13 #include <errno.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <netdb.h>
17 #include <arpa/inet.h>
18
19 #define MAXARGS   1000
20
21 /*
22  * static prototypes
23  */
24
25 /* client's own static version of several nmh subroutines */
26 static char **client_brkstring (char *, char *, char *);
27 static int client_brkany (char, char *);
28 static char **client_copyip (char **, char **, int);
29 static char *client_getcpy (char *);
30 static void client_freelist(char **);
31
32
33 int
34 client (char *args, char *service, char *response, int len_response, int debug)
35 {
36     int sd, rc;
37     char **ap, *arguments[MAXARGS];
38     struct addrinfo hints, *res, *ai;
39
40     ap = arguments;
41     if (args != NULL && *args != 0) {
42         ap = client_copyip (client_brkstring (client_getcpy (args), " ", "\n"),
43                 ap, MAXARGS);
44     } else {
45         if (servers != NULL && *servers != 0)
46             ap = client_copyip (client_brkstring (client_getcpy (servers), " ", "\n"),
47                 ap, MAXARGS);
48     }
49     if (ap == arguments) {
50         *ap++ = client_getcpy ("localhost");
51         *ap = NULL;
52     }
53
54     memset(&hints, 0, sizeof(hints));
55 #ifdef AI_ADDRCONFIG
56     hints.ai_flags = AI_ADDRCONFIG;
57 #endif
58     hints.ai_family = PF_UNSPEC;
59     hints.ai_socktype = SOCK_STREAM;
60
61     for (ap = arguments; *ap; ap++) {
62
63         if (debug) {
64             fprintf(stderr, "Trying to connect to \"%s\" ...\n", *ap);
65         }
66
67         rc = getaddrinfo(*ap, service, &hints, &res);
68
69         if (rc) {
70             if (debug) {
71                 fprintf(stderr, "Lookup of \"%s\" failed: %s\n", *ap,
72                         gai_strerror(rc));
73             }
74             continue;
75         }
76
77         for (ai = res; ai != NULL; ai = ai->ai_next) {
78             if (debug) {
79                 char address[NI_MAXHOST];
80
81                 rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, address,
82                                  sizeof(address), NULL, 0, NI_NUMERICHOST);
83
84                 fprintf(stderr, "Connecting to %s...\n",
85                         rc ? "unknown" : address);
86             }
87
88             sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
89
90             if (sd < 0) {
91                 if (debug)
92                     fprintf(stderr, "socket() failed: %s\n", strerror(errno));
93                 continue;
94             }
95
96             if (connect(sd, ai->ai_addr, ai->ai_addrlen) == 0) {
97                 freeaddrinfo(res);
98                 client_freelist(ap);
99                 return sd;
100             }
101
102             if (debug) {
103                 fprintf(stderr, "Connection failed: %s\n", strerror(errno));
104             }
105
106             close(sd);
107         }
108
109         freeaddrinfo(res);
110     }
111
112     client_freelist(ap);
113     strncpy (response, "no servers available", len_response);
114     return NOTOK;
115 }
116
117
118 /*
119  * Free a list of strings
120  */
121
122 static void
123 client_freelist(char **list)
124 {
125     while (*list++ != NULL)
126         free(*list);
127 }
128
129
130 /*
131  * static copies of three nmh subroutines
132  */
133
134 static char *broken[MAXARGS + 1];
135
136 static char **
137 client_brkstring (char *strg, char *brksep, char *brkterm)
138 {
139     register int bi;
140     register char c, *sp;
141
142     sp = strg;
143
144     for (bi = 0; bi < MAXARGS; bi++) {
145         while (client_brkany (c = *sp, brksep))
146             *sp++ = 0;
147         if (!c || client_brkany (c, brkterm)) {
148             *sp = 0;
149             broken[bi] = 0;
150             return broken;
151         }
152
153         broken[bi] = sp;
154         while ((c = *++sp) && !client_brkany (c, brksep) && !client_brkany (c, brkterm))
155             continue;
156     }
157     broken[MAXARGS] = 0;
158
159     return broken;
160 }
161
162
163 /*
164  * returns 1 if chr in strg, 0 otherwise
165  */
166 static int
167 client_brkany (char chr, char *strg)
168 {
169     register char *sp;
170  
171     if (strg)
172         for (sp = strg; *sp; sp++)
173             if (chr == *sp)
174                 return 1;
175     return 0;
176 }
177
178
179 /*
180  * copy a string array and return pointer to end
181  */
182 static char **
183 client_copyip (char **p, char **q, int len_q)
184 {
185     while (*p && --len_q > 0)
186         *q++ = *p++;
187
188     *q = NULL;
189
190     return q;
191 }
192
193
194 static char *
195 client_getcpy (char *str)
196 {
197     char *cp;
198     size_t len;
199
200     len = strlen(str) + 1;
201     cp = mh_xmalloc(len);
202
203     memcpy (cp, str, len);
204     return cp;
205 }
206