1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23#include "setup.h"
24
25#ifndef CURL_DISABLE_DICT
26
27/* -- WIN32 approved -- */
28#include <stdio.h>
29#include <string.h>
30#include <stdarg.h>
31#include <stdlib.h>
32#include <ctype.h>
33
34#ifdef WIN32
35#include <time.h>
36#include <io.h>
37#else
38#ifdef HAVE_SYS_SOCKET_H
39#include <sys/socket.h>
40#endif
41#include <netinet/in.h>
42#ifdef HAVE_SYS_TIME_H
43#include <sys/time.h>
44#endif
45#ifdef HAVE_UNISTD_H
46#include <unistd.h>
47#endif
48#include <netdb.h>
49#ifdef HAVE_ARPA_INET_H
50#include <arpa/inet.h>
51#endif
52#ifdef HAVE_NET_IF_H
53#include <net/if.h>
54#endif
55#ifdef HAVE_SYS_IOCTL_H
56#include <sys/ioctl.h>
57#endif
58
59#ifdef HAVE_SYS_PARAM_H
60#include <sys/param.h>
61#endif
62
63#ifdef HAVE_SYS_SELECT_H
64#include <sys/select.h>
65#endif
66
67
68#endif
69
70#include "urldata.h"
71#include <curl/curl.h>
72#include "transfer.h"
73#include "sendf.h"
74
75#include "progress.h"
76#include "strequal.h"
77#include "dict.h"
78#include "rawstr.h"
79
80#define _MPRINTF_REPLACE /* use our functions only */
81#include <curl/mprintf.h>
82
83/* The last #include file should be: */
84#include "memdebug.h"
85
86
87/*
88 * Forward declarations.
89 */
90
91static CURLcode dict_do(struct connectdata *conn, bool *done);
92
93/*
94 * DICT protocol handler.
95 */
96
97const struct Curl_handler Curl_handler_dict = {
98  "DICT",                               /* scheme */
99  ZERO_NULL,                            /* setup_connection */
100  dict_do,                              /* do_it */
101  ZERO_NULL,                            /* done */
102  ZERO_NULL,                            /* do_more */
103  ZERO_NULL,                            /* connect_it */
104  ZERO_NULL,                            /* connecting */
105  ZERO_NULL,                            /* doing */
106  ZERO_NULL,                            /* proto_getsock */
107  ZERO_NULL,                            /* doing_getsock */
108  ZERO_NULL,                            /* perform_getsock */
109  ZERO_NULL,                            /* disconnect */
110  ZERO_NULL,                            /* readwrite */
111  PORT_DICT,                            /* defport */
112  CURLPROTO_DICT,                       /* protocol */
113  PROTOPT_NONE                          /* flags */
114};
115
116static char *unescape_word(struct SessionHandle *data, const char *inputbuff)
117{
118  char *newp;
119  char *dictp;
120  char *ptr;
121  int len;
122  char byte;
123  int olen=0;
124
125  newp = curl_easy_unescape(data, inputbuff, 0, &len);
126  if(!newp)
127    return NULL;
128
129  dictp = malloc(((size_t)len)*2 + 1); /* add one for terminating zero */
130  if(dictp) {
131    /* According to RFC2229 section 2.2, these letters need to be escaped with
132       \[letter] */
133    for(ptr = newp;
134        (byte = *ptr) != 0;
135        ptr++) {
136      if((byte <= 32) || (byte == 127) ||
137          (byte == '\'') || (byte == '\"') || (byte == '\\')) {
138        dictp[olen++] = '\\';
139      }
140      dictp[olen++] = byte;
141    }
142    dictp[olen]=0;
143
144    free(newp);
145  }
146  return dictp;
147}
148
149static CURLcode dict_do(struct connectdata *conn, bool *done)
150{
151  char *word;
152  char *eword;
153  char *ppath;
154  char *database = NULL;
155  char *strategy = NULL;
156  char *nthdef = NULL; /* This is not part of the protocol, but required
157                          by RFC 2229 */
158  CURLcode result=CURLE_OK;
159  struct SessionHandle *data=conn->data;
160  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
161
162  char *path = data->state.path;
163  curl_off_t *bytecount = &data->req.bytecount;
164
165  *done = TRUE; /* unconditionally */
166
167  if(conn->bits.user_passwd) {
168    /* AUTH is missing */
169  }
170
171  if(Curl_raw_nequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
172      Curl_raw_nequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
173      Curl_raw_nequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
174
175    word = strchr(path, ':');
176    if(word) {
177      word++;
178      database = strchr(word, ':');
179      if(database) {
180        *database++ = (char)0;
181        strategy = strchr(database, ':');
182        if(strategy) {
183          *strategy++ = (char)0;
184          nthdef = strchr(strategy, ':');
185          if(nthdef) {
186            *nthdef = (char)0;
187          }
188        }
189      }
190    }
191
192    if((word == NULL) || (*word == (char)0)) {
193      infof(data, "lookup word is missing");
194      word=(char *)"default";
195    }
196    if((database == NULL) || (*database == (char)0)) {
197      database = (char *)"!";
198    }
199    if((strategy == NULL) || (*strategy == (char)0)) {
200      strategy = (char *)".";
201    }
202
203    eword = unescape_word(data, word);
204    if(!eword)
205      return CURLE_OUT_OF_MEMORY;
206
207    result = Curl_sendf(sockfd, conn,
208                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
209                        "MATCH "
210                        "%s "    /* database */
211                        "%s "    /* strategy */
212                        "%s\r\n" /* word */
213                        "QUIT\r\n",
214
215                        database,
216                        strategy,
217                        eword
218                        );
219
220    free(eword);
221
222    if(result) {
223      failf(data, "Failed sending DICT request");
224      return result;
225    }
226    Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
227                        -1, NULL); /* no upload */
228  }
229  else if(Curl_raw_nequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
230           Curl_raw_nequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
231           Curl_raw_nequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
232
233    word = strchr(path, ':');
234    if(word) {
235      word++;
236      database = strchr(word, ':');
237      if(database) {
238        *database++ = (char)0;
239        nthdef = strchr(database, ':');
240        if(nthdef) {
241          *nthdef = (char)0;
242        }
243      }
244    }
245
246    if((word == NULL) || (*word == (char)0)) {
247      infof(data, "lookup word is missing");
248      word=(char *)"default";
249    }
250    if((database == NULL) || (*database == (char)0)) {
251      database = (char *)"!";
252    }
253
254    eword = unescape_word(data, word);
255    if(!eword)
256      return CURLE_OUT_OF_MEMORY;
257
258    result = Curl_sendf(sockfd, conn,
259                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
260                        "DEFINE "
261                        "%s "     /* database */
262                        "%s\r\n"  /* word */
263                        "QUIT\r\n",
264                        database,
265                        eword);
266
267    free(eword);
268
269    if(result) {
270      failf(data, "Failed sending DICT request");
271      return result;
272    }
273    Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
274                        -1, NULL); /* no upload */
275  }
276  else {
277
278    ppath = strchr(path, '/');
279    if(ppath) {
280      int i;
281
282      ppath++;
283      for(i = 0; ppath[i]; i++) {
284        if(ppath[i] == ':')
285          ppath[i] = ' ';
286      }
287      result = Curl_sendf(sockfd, conn,
288                          "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
289                          "%s\r\n"
290                          "QUIT\r\n", ppath);
291      if(result) {
292        failf(data, "Failed sending DICT request");
293        return result;
294      }
295
296      Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, -1, NULL);
297    }
298  }
299
300  return CURLE_OK;
301}
302#endif /*CURL_DISABLE_DICT*/
303