1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2012, 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 "curl_setup.h"
24
25#ifndef CURL_DISABLE_DICT
26
27#ifdef HAVE_NETINET_IN_H
28#include <netinet/in.h>
29#endif
30#ifdef HAVE_NETDB_H
31#include <netdb.h>
32#endif
33#ifdef HAVE_ARPA_INET_H
34#include <arpa/inet.h>
35#endif
36#ifdef HAVE_NET_IF_H
37#include <net/if.h>
38#endif
39#ifdef HAVE_SYS_IOCTL_H
40#include <sys/ioctl.h>
41#endif
42
43#ifdef HAVE_SYS_PARAM_H
44#include <sys/param.h>
45#endif
46
47#ifdef HAVE_SYS_SELECT_H
48#include <sys/select.h>
49#endif
50
51#include "urldata.h"
52#include <curl/curl.h>
53#include "transfer.h"
54#include "sendf.h"
55
56#include "progress.h"
57#include "strequal.h"
58#include "dict.h"
59#include "rawstr.h"
60
61#define _MPRINTF_REPLACE /* use our functions only */
62#include <curl/mprintf.h>
63
64#include "curl_memory.h"
65/* The last #include file should be: */
66#include "memdebug.h"
67
68/*
69 * Forward declarations.
70 */
71
72static CURLcode dict_do(struct connectdata *conn, bool *done);
73
74/*
75 * DICT protocol handler.
76 */
77
78const struct Curl_handler Curl_handler_dict = {
79  "DICT",                               /* scheme */
80  ZERO_NULL,                            /* setup_connection */
81  dict_do,                              /* do_it */
82  ZERO_NULL,                            /* done */
83  ZERO_NULL,                            /* do_more */
84  ZERO_NULL,                            /* connect_it */
85  ZERO_NULL,                            /* connecting */
86  ZERO_NULL,                            /* doing */
87  ZERO_NULL,                            /* proto_getsock */
88  ZERO_NULL,                            /* doing_getsock */
89  ZERO_NULL,                            /* domore_getsock */
90  ZERO_NULL,                            /* perform_getsock */
91  ZERO_NULL,                            /* disconnect */
92  ZERO_NULL,                            /* readwrite */
93  PORT_DICT,                            /* defport */
94  CURLPROTO_DICT,                       /* protocol */
95  PROTOPT_NONE | PROTOPT_NOURLQUERY      /* flags */
96};
97
98static char *unescape_word(struct SessionHandle *data, const char *inputbuff)
99{
100  char *newp;
101  char *dictp;
102  char *ptr;
103  int len;
104  char byte;
105  int olen=0;
106
107  newp = curl_easy_unescape(data, inputbuff, 0, &len);
108  if(!newp)
109    return NULL;
110
111  dictp = malloc(((size_t)len)*2 + 1); /* add one for terminating zero */
112  if(dictp) {
113    /* According to RFC2229 section 2.2, these letters need to be escaped with
114       \[letter] */
115    for(ptr = newp;
116        (byte = *ptr) != 0;
117        ptr++) {
118      if((byte <= 32) || (byte == 127) ||
119          (byte == '\'') || (byte == '\"') || (byte == '\\')) {
120        dictp[olen++] = '\\';
121      }
122      dictp[olen++] = byte;
123    }
124    dictp[olen]=0;
125
126    free(newp);
127  }
128  return dictp;
129}
130
131static CURLcode dict_do(struct connectdata *conn, bool *done)
132{
133  char *word;
134  char *eword;
135  char *ppath;
136  char *database = NULL;
137  char *strategy = NULL;
138  char *nthdef = NULL; /* This is not part of the protocol, but required
139                          by RFC 2229 */
140  CURLcode result=CURLE_OK;
141  struct SessionHandle *data=conn->data;
142  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
143
144  char *path = data->state.path;
145  curl_off_t *bytecount = &data->req.bytecount;
146
147  *done = TRUE; /* unconditionally */
148
149  if(conn->bits.user_passwd) {
150    /* AUTH is missing */
151  }
152
153  if(Curl_raw_nequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
154      Curl_raw_nequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
155      Curl_raw_nequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
156
157    word = strchr(path, ':');
158    if(word) {
159      word++;
160      database = strchr(word, ':');
161      if(database) {
162        *database++ = (char)0;
163        strategy = strchr(database, ':');
164        if(strategy) {
165          *strategy++ = (char)0;
166          nthdef = strchr(strategy, ':');
167          if(nthdef) {
168            *nthdef = (char)0;
169          }
170        }
171      }
172    }
173
174    if((word == NULL) || (*word == (char)0)) {
175      infof(data, "lookup word is missing\n");
176      word=(char *)"default";
177    }
178    if((database == NULL) || (*database == (char)0)) {
179      database = (char *)"!";
180    }
181    if((strategy == NULL) || (*strategy == (char)0)) {
182      strategy = (char *)".";
183    }
184
185    eword = unescape_word(data, word);
186    if(!eword)
187      return CURLE_OUT_OF_MEMORY;
188
189    result = Curl_sendf(sockfd, conn,
190                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
191                        "MATCH "
192                        "%s "    /* database */
193                        "%s "    /* strategy */
194                        "%s\r\n" /* word */
195                        "QUIT\r\n",
196
197                        database,
198                        strategy,
199                        eword
200                        );
201
202    free(eword);
203
204    if(result) {
205      failf(data, "Failed sending DICT request");
206      return result;
207    }
208    Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
209                        -1, NULL); /* no upload */
210  }
211  else if(Curl_raw_nequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
212           Curl_raw_nequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
213           Curl_raw_nequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
214
215    word = strchr(path, ':');
216    if(word) {
217      word++;
218      database = strchr(word, ':');
219      if(database) {
220        *database++ = (char)0;
221        nthdef = strchr(database, ':');
222        if(nthdef) {
223          *nthdef = (char)0;
224        }
225      }
226    }
227
228    if((word == NULL) || (*word == (char)0)) {
229      infof(data, "lookup word is missing\n");
230      word=(char *)"default";
231    }
232    if((database == NULL) || (*database == (char)0)) {
233      database = (char *)"!";
234    }
235
236    eword = unescape_word(data, word);
237    if(!eword)
238      return CURLE_OUT_OF_MEMORY;
239
240    result = Curl_sendf(sockfd, conn,
241                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
242                        "DEFINE "
243                        "%s "     /* database */
244                        "%s\r\n"  /* word */
245                        "QUIT\r\n",
246                        database,
247                        eword);
248
249    free(eword);
250
251    if(result) {
252      failf(data, "Failed sending DICT request");
253      return result;
254    }
255    Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
256                        -1, NULL); /* no upload */
257  }
258  else {
259
260    ppath = strchr(path, '/');
261    if(ppath) {
262      int i;
263
264      ppath++;
265      for(i = 0; ppath[i]; i++) {
266        if(ppath[i] == ':')
267          ppath[i] = ' ';
268      }
269      result = Curl_sendf(sockfd, conn,
270                          "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
271                          "%s\r\n"
272                          "QUIT\r\n", ppath);
273      if(result) {
274        failf(data, "Failed sending DICT request");
275        return result;
276      }
277
278      Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, -1, NULL);
279    }
280  }
281
282  return CURLE_OK;
283}
284#endif /*CURL_DISABLE_DICT*/
285