/*************************************************************************** * * Copyright 2001,2011,2013 by Sean Conner. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or (at your * option) any later version. * * This library 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. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, see . * * Comments, questions and criticisms can be sent to: sean@conman.org * *************************************************************************/ #ifdef __GNUC__ # define _GNU_SOURCE #endif #include #include #include #include #include #include "../url.h" /**********************************************************************/ static int gopher_new (url__t *restrict,char const *restrict); static int gopher_compare (url__t const *const restrict,url__t const *const restrict); static size_t gopher_makestring (url__t const *const restrict,char *restrict,size_t); static void gopher_free (url__t *); /***********************************************************************/ struct urlvector const g_gophervec = { gopher_new, gopher_compare, gopher_makestring, gopher_free }; /********************************************************************/ static int gopher_new(url__t *restrict url,char const *surl) { urlgopher__t *hurl = &url->gopher; char *next; char tmpbuf[BUFSIZ]; size_t tmpsz; size_t len; assert(url != NULL); assert(surl != NULL); /*------------------------------------------------ ; host portion, if any ;-------------------------------------------------*/ UrlGetHost(tmpbuf,BUFSIZ,&surl); hurl->host = strdup(tmpbuf); /*------------------------------------------------------- ; optional port number ;------------------------------------------------------*/ tmpsz = UrlGetPort(tmpbuf,BUFSIZ,&surl); if (tmpsz) { long lport; errno = 0; lport = strtol(tmpbuf,NULL,10); if ((errno == ERANGE) && ((lport == LONG_MAX) || (lport == LONG_MIN))) return(ERANGE); if ((lport < 0) || (lport > PORTMAX)) return(EDOM); hurl->port = lport; } else hurl->port = 70; if (*surl == '\0') { hurl->type = GOPHER_DIR; hurl->selector = strdup(""); hurl->search = strdup(""); hurl->plus = strdup(""); return 0; } else if (*surl != '/') { free(hurl->host); return EINVAL; } surl++; /*------------------------------------------------------------------ ; parse the type ;-----------------------------------------------------------------*/ hurl->type = *surl++; /*------------------------------------ ; Path (actually, the selector) ;-------------------------------------*/ next = strstr(surl,"%09"); if (next == NULL) { hurl->selector = strdup(surl); hurl->search = strdup(""); hurl->plus = strdup(""); return 0; } /*----------------------------------------------------------------------- ; We found the '%09', copy everything up to it in selector, and bump past it. ;------------------------------------------------------------------------*/ len = (size_t)(next - surl) + 1; hurl->selector = malloc(len); if (hurl->selector == NULL) { free(hurl->host); return ENOMEM; } memcpy(hurl->selector,surl,len); surl += 3; /*------------------------------------------ ; if we're up against Sark, return an error. ;-------------------------------------------*/ if (*surl == '\0') { free(hurl->selector); free(hurl->host); return EINVAL; } /*-------------------------------- ; handle the search portion ;---------------------------------*/ next = strstr(surl,"%09"); if (next == NULL) { hurl->search = strdup(surl); hurl->plus = strdup(""); return 0; } /*------------------------------ ; we have a plus selector! ;-------------------------------*/ len = (size_t)(next - surl) + 1; hurl->search = malloc(len); if (hurl->search == NULL) { free(hurl->selector); free(hurl->host); return ENOMEM; } memcpy(hurl->search,surl,len); surl += 3; if (*surl == '\0') { free(hurl->search); free(hurl->selector); free(hurl->host); return EINVAL; } hurl->plus = strdup(surl); return 0; } /**********************************************************************/ static int gopher_compare( url__t const *const restrict durl, url__t const *const restrict surl ) { int rc; assert(durl != NULL); assert(durl->scheme == URL_GOPHER); assert(surl != NULL); assert(surl->scheme < URL_max); rc = durl->scheme - surl->scheme; if (rc != 0) return rc; rc = strcmp(durl->gopher.host,surl->gopher.host); if (rc != 0) return rc; rc = durl->gopher.port - surl->gopher.port; if (rc != 0) return rc; rc = durl->gopher.type - surl->gopher.type; if (rc != 0) return rc; rc = strcmp(durl->gopher.selector,surl->gopher.selector); if (rc != 0) return rc; rc = strcmp(durl->gopher.search,surl->gopher.search); if (rc != 0) return rc; return strcmp(durl->gopher.plus,surl->gopher.plus); } /**********************************************************************/ static size_t gopher_makestring( url__t const *const restrict url, char *restrict d, size_t sd ) { char port[7]; assert(url != NULL); assert(url->scheme == URL_GOPHER); assert(url->gopher.host != NULL); assert(url->gopher.port >= 0); assert(url->gopher.port <= PORTMAX); assert(url->gopher.type != '\0'); assert(url->gopher.selector != NULL); assert(url->gopher.search != NULL); assert(url->gopher.plus != NULL); assert(d != NULL); assert(sd > 0); if (url->gopher.port == 70) port[0] = '\0'; else snprintf(port,sizeof(port),":%d",url->gopher.port); return snprintf( d, sd, /* h N t p > s > + */ "gopher://%s%s/%c%s%s%s%s%s", url->gopher.host, port, url->gopher.type, url->gopher.selector, (*url->gopher.search != '\0') ? "%09" : "", url->gopher.search, (*url->gopher.plus != '\0') ? "%09" : "", url->gopher.plus ); } /***********************************************************************/ static void gopher_free(url__t *url) { assert(url != NULL); assert(url->scheme == URL_GOPHER); free(url->gopher.host); free(url->gopher.selector); free(url->gopher.search); free(url->gopher.plus); free(url); } /*************************************************************************/ .