/* ** Copyright (c) 2007 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** This program is distributed in the hope that it will be useful, ** but without any warranty; without even the implied warranty of ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code for parsing URLs that appear on the command-line */ #include "config.h" #include "url.h" /* ** Convert a string to lower-case. */ static void url_tolower(char *z){ while( *z ){ *z = fossil_tolower(*z); z++; } } /* ** Parse the given URL. Populate variables in the global "g" structure. ** ** g.urlIsFile True if FILE: ** g.urlIsHttps True if HTTPS: ** g.urlIsSsh True if SSH: ** g.urlProtocol "http" or "https" or "file" ** g.urlName Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE: ** g.urlPort TCP port number for HTTP or HTTPS. ** g.urlDfltPort Default TCP port number (80 or 443). ** g.urlPath Path name for HTTP or HTTPS. ** g.urlUser Userid. ** g.urlPasswd Password. ** g.urlHostname HOST:PORT or just HOST if port is the default. ** g.urlCanonical The URL in canonical form, omitting the password ** ** HTTP url format is: ** ** http://userid:password@host:port/path ** ** SSH url format is: ** ** ssh://userid:password@host:port/path?fossil=path/to/fossil.exe ** */ void url_parse(const char *zUrl){ int i, j, c; char *zFile = 0; if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 || strncmp(zUrl, "ssh://", 6)==0 ){ int iStart; char *zLogin; char *zExe; g.urlIsFile = 0; if( zUrl[4]=='s' ){ g.urlIsHttps = 1; g.urlProtocol = "https"; g.urlDfltPort = 443; iStart = 8; }else if( zUrl[0]=='s' ){ g.urlIsSsh = 1; g.urlProtocol = "ssh"; g.urlDfltPort = 22; g.urlFossil = "fossil"; iStart = 6; }else{ g.urlIsHttps = 0; g.urlProtocol = "http"; g.urlDfltPort = 80; iStart = 7; } for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){} if( c=='@' ){ /* Parse up the user-id and password */ for(j=iStart; jurl); p->zBase = zBase; p->nParam = 0; } /* ** Add a fixed parameter to an HQuery. */ void url_add_parameter(HQuery *p, const char *zName, const char *zValue){ assert( p->nParam < count(p->azName) ); assert( p->nParam < count(p->azValue) ); p->azName[p->nParam] = zName; p->azValue[p->nParam] = zValue; p->nParam++; } /* ** Render the URL with a parameter override. */ char *url_render( HQuery *p, /* Base URL */ const char *zName1, /* First override */ const char *zValue1, /* First override value */ const char *zName2, /* Second override */ const char *zValue2 /* Second override value */ ){ const char *zSep = "?"; int i; blob_reset(&p->url); blob_appendf(&p->url, "%s/%s", g.zTop, p->zBase); for(i=0; inParam; i++){ const char *z = p->azValue[i]; if( zName1 && fossil_strcmp(zName1,p->azName[i])==0 ){ zName1 = 0; z = zValue1; if( z==0 ) continue; } if( zName2 && fossil_strcmp(zName2,p->azName[i])==0 ){ zName2 = 0; z = zValue2; if( z==0 ) continue; } blob_appendf(&p->url, "%s%s", zSep, p->azName[i]); if( z && z[0] ) blob_appendf(&p->url, "=%T", z); zSep = "&"; } if( zName1 && zValue1 ){ blob_appendf(&p->url, "%s%s", zSep, zName1); if( zValue1[0] ) blob_appendf(&p->url, "=%T", zValue1); } if( zName2 && zValue2 ){ blob_appendf(&p->url, "%s%s", zSep, zName2); if( zValue2[0] ) blob_appendf(&p->url, "=%T", zValue2); } return blob_str(&p->url); } /* ** Prompt the user for the password for g.urlUser. Store the result ** in g.urlPasswd. */ void url_prompt_for_password(void){ if( isatty(fileno(stdin)) ){ char *zPrompt = mprintf("\rpassword for %s: ", g.urlUser); Blob x; prompt_for_password(zPrompt, &x, 0); free(zPrompt); g.urlPasswd = mprintf("%b", &x); blob_reset(&x); }else{ fossil_fatal("missing or incorrect password for user \"%s\"", g.urlUser); } } /* Preemptively prompt for a password if a username is given in the ** URL but no password. */ void url_get_password_if_needed(void){ if( (g.urlUser && g.urlUser[0]) && (g.urlPasswd==0 || g.urlPasswd[0]==0) && isatty(fileno(stdin)) && g.urlIsSsh==0 ){ url_prompt_for_password(); } }