1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2013, 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#include "tool_setup.h"
23
24#include "rawstr.h"
25
26#define ENABLE_CURLX_PRINTF
27/* use our own printf() functions */
28#include "curlx.h"
29
30#include "tool_cfgable.h"
31#include "tool_convert.h"
32#include "tool_operhlp.h"
33#include "tool_version.h"
34#include "tool_metalink.h"
35
36#include "memdebug.h" /* keep this as LAST include */
37
38/*
39 * my_useragent: returns allocated string with default user agent
40 */
41char *my_useragent(void)
42{
43  return strdup( CURL_NAME "/" CURL_VERSION );
44}
45
46/*
47 * Print list of OpenSSL supported engines
48 */
49void list_engines(const struct curl_slist *engines)
50{
51  puts("Build-time engines:");
52  if(!engines) {
53    puts("  <none>");
54    return;
55  }
56  for(; engines; engines = engines->next)
57    printf("  %s\n", engines->data);
58}
59
60void clean_getout(struct Configurable *config)
61{
62  struct getout *next;
63  struct getout *node = config->url_list;
64
65  while(node) {
66    next = node->next;
67    Curl_safefree(node->url);
68    Curl_safefree(node->outfile);
69    Curl_safefree(node->infile);
70    Curl_safefree(node);
71    node = next;
72  }
73  config->url_list = NULL;
74}
75
76bool output_expected(const char *url, const char *uploadfile)
77{
78  if(!uploadfile)
79    return TRUE;  /* download */
80  if(checkprefix("http://", url) || checkprefix("https://", url))
81    return TRUE;   /* HTTP(S) upload */
82
83  return FALSE; /* non-HTTP upload, probably no output should be expected */
84}
85
86bool stdin_upload(const char *uploadfile)
87{
88  return (curlx_strequal(uploadfile, "-") ||
89          curlx_strequal(uploadfile, ".")) ? TRUE : FALSE;
90}
91
92/*
93 * Adds the file name to the URL if it doesn't already have one.
94 * url will be freed before return if the returned pointer is different
95 */
96char *add_file_name_to_url(CURL *curl, char *url, const char *filename)
97{
98  /* If no file name part is given in the URL, we add this file name */
99  char *ptr = strstr(url, "://");
100  if(ptr)
101    ptr += 3;
102  else
103    ptr = url;
104  ptr = strrchr(ptr, '/');
105  if(!ptr || !strlen(++ptr)) {
106    /* The URL has no file name part, add the local file name. In order
107       to be able to do so, we have to create a new URL in another
108       buffer.*/
109
110    /* We only want the part of the local path that is on the right
111       side of the rightmost slash and backslash. */
112    const char *filep = strrchr(filename, '/');
113    char *file2 = strrchr(filep?filep:filename, '\\');
114    char *encfile;
115
116    if(file2)
117      filep = file2 + 1;
118    else if(filep)
119      filep++;
120    else
121      filep = filename;
122
123    /* URL encode the file name */
124    encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
125    if(encfile) {
126      char *urlbuffer;
127      if(ptr)
128        /* there is a trailing slash on the URL */
129        urlbuffer = aprintf("%s%s", url, encfile);
130      else
131        /* there is no trailing slash on the URL */
132        urlbuffer = aprintf("%s/%s", url, encfile);
133
134      curl_free(encfile);
135      Curl_safefree(url);
136
137      if(!urlbuffer)
138        return NULL;
139
140      url = urlbuffer; /* use our new URL instead! */
141    }
142  }
143  return url;
144}
145
146/* Extracts the name portion of the URL.
147 * Returns a pointer to a heap-allocated string or NULL if
148 * no name part, at location indicated by first argument.
149 */
150CURLcode get_url_file_name(char **filename, const char *url)
151{
152  const char *pc;
153
154  *filename = NULL;
155
156  /* Find and get the remote file name */
157  pc = strstr(url, "://");
158  if(pc)
159    pc += 3;
160  else
161    pc = url;
162  pc = strrchr(pc, '/');
163
164  if(pc) {
165    /* duplicate the string beyond the slash */
166    pc++;
167    if(*pc) {
168      *filename = strdup(pc);
169      if(!*filename)
170        return CURLE_OUT_OF_MEMORY;
171    }
172  }
173
174  /* in case we built debug enabled, we allow an environment variable
175   * named CURL_TESTDIR to prefix the given file name to put it into a
176   * specific directory
177   */
178#ifdef DEBUGBUILD
179  {
180    char *tdir = curlx_getenv("CURL_TESTDIR");
181    if(tdir) {
182      char buffer[512]; /* suitably large */
183      snprintf(buffer, sizeof(buffer), "%s/%s", tdir, *filename);
184      Curl_safefree(*filename);
185      *filename = strdup(buffer); /* clone the buffer */
186      curl_free(tdir);
187    }
188  }
189#endif
190
191  return CURLE_OK;
192}
193
194/*
195 * This is the main global constructor for the app. Call this before
196 * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
197 * used, or havoc may be the result.
198 */
199CURLcode main_init(void)
200{
201#if defined(__DJGPP__) || defined(__GO32__)
202  /* stop stat() wasting time */
203  _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
204#endif
205
206  return curl_global_init(CURL_GLOBAL_DEFAULT);
207}
208
209/*
210 * This is the main global destructor for the app. Call this after
211 * _all_ libcurl usage is done.
212 */
213void main_free(void)
214{
215  curl_global_cleanup();
216  convert_cleanup();
217  metalink_cleanup();
218}
219
220#ifdef CURLDEBUG
221void memory_tracking_init(void)
222{
223  char *env;
224  /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */
225  env = curlx_getenv("CURL_MEMDEBUG");
226  if(env) {
227    /* use the value as file name */
228    char fname[CURL_MT_LOGFNAME_BUFSIZE];
229    if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE)
230      env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0';
231    strcpy(fname, env);
232    curl_free(env);
233    curl_memdebug(fname);
234    /* this weird stuff here is to make curl_free() get called
235       before curl_memdebug() as otherwise memory tracking will
236       log a free() without an alloc! */
237  }
238  /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */
239  env = curlx_getenv("CURL_MEMLIMIT");
240  if(env) {
241    char *endptr;
242    long num = strtol(env, &endptr, 10);
243    if((endptr != env) && (endptr == env + strlen(env)) && (num > 0))
244      curl_memlimit(num);
245    curl_free(env);
246  }
247}
248#endif
249
250