/* Copyright 1997 Acorn Computers Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /***************************************************/ /* File : URLutils.c */ /* */ /* Purpose: URL manipulation for the browser. */ /* */ /* Author : Merlyn Kline for Customer browser */ /* This source adapted by A.D.Hodgkinson */ /* from various original functions */ /* */ /* History: 06-Feb-97: Created. */ /***************************************************/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include "swis.h" #include "URI.h" /* URI handler API, in URILib:h */ #include "wimp.h" #include "event.h" #include "svcprint.h" #include "Global.h" #include "Utils.h" #include "Fetch.h" /* (Which itself includes URLstat.h) */ #include "Filetypes.h" #include "MimeMap.h" #include "URLveneer.h" #include "URLutils.h" /* Local definitions */ #define ExtensionMatches(url, len, ext) (len) > strlen(ext) && !strncmp((url) + (len) - strlen(ext), (ext), strlen(ext)) /* Local variables */ /* Pointer to first item in queue of URLs dispatched through */ /* the URI handler (structure defined in URLutils.h) */ static uri_queue * uri_queue_base = NULL; /*************************************************/ /* urlutils_urlsscmp() */ /* */ /* Compares two URLs, returning 1 if they differ */ /* or 0 if they are the same. Both URLs are */ /* converted internally to url_descriptions. */ /* */ /* Parameters: Pointer to a null terminated URL */ /* string; */ /* */ /* Pointer to a second null termina- */ /* ted URL string. */ /* */ /* Returns: 0 if the URLs match, else 1. */ /*************************************************/ int urlutils_urlsscmp(const char * url_s1, const char * url_s2) { url_description * url_d1; url_description * url_d2; int result; /* Sanity check */ if (!url_s1 && !url_s2) return 0; if (!url_s1 || !url_s2) return 1; // Awaiting URL module stuff url_d1 = urlutils_return_description(url_s1); url_d2 = urlutils_return_description(url_s2); if (url_d1 && url_d2) { result = !!strcmp(url_d1->full, url_d2->full); } /* No memory, no brain. Hey ho. */ else result = !!strcmp(url_s1, url_s2); free(url_d1); free(url_d2); return result; } /*************************************************/ /* urlutils_urldscmp() */ /* */ /* Compares two URLs, returning 1 if they differ */ /* or 0 if they are the same. The first URL is */ /* specified as a url_description, the second */ /* URL is converted internally. */ /* */ /* Parameters: Pointer to a url_description */ /* filled in with the URL details; */ /* */ /* Pointer to a second null termina- */ /* ted URL string. */ /* */ /* Returns: 0 if the URLs match, else 1. */ /*************************************************/ int urlutils_urldscmp(const url_description * url_d, const char * url_s) { url_description * url_d2; int result; /* Sanity check */ if (!url_d) return 1; if (!url_s && !url_d->full) return 0; if (!url_s || !url_d->full) return 1; // Awaiting URL module stuff url_d2 = urlutils_return_description(url_s); if (url_d && url_d2) { result = !!strcmp(url_d->full, url_d2->full); } else result = !!strcmp(url_d->full, url_s); free(url_d2); return result; } /*************************************************/ /* urlutils_urldscmp() */ /* */ /* Compares two URLs, returning 1 if they differ */ /* or 0 if they are the same. Both URLs are */ /* specified as url_description structures. */ /* */ /* Parameters: Pointer to a url_description */ /* filled in with the URL details; */ /* */ /* Another url_description pointer, */ /* filled in with the details of a */ /* second URL. */ /* */ /* Returns: 0 if the URLs match, else 1. */ /*************************************************/ int urlutils_urlddcmp(const url_description * url_d1, const url_description * url_d2) { /* Sanity check */ if (!url_d1 && url_d2) return 1; if (!url_d2 && url_d1) return 1; if (!url_d1 && !url_d2) return 0; if (!url_d1->full && !url_d2->full) return 0; if (!url_d1->full || !url_d2->full) return 1; // Awaiting URL module stuff return !!strcmp(url_d1->full, url_d2->full); } /*************************************************/ /* urlutils_return_description() */ /* */ /* Given a URL string, returns a url_description */ /* structure which contains more accessible */ /* details on the URL contents. */ /* */ /* The block itself and all filled in fields are */ /* allocated with malloc(), and any additions to */ /* the structure should be allocated in the same */ /* way. */ /* */ /* Parameters: Pointer to a null terminated URL */ /* string. */ /* */ /* Returns: Pointer to a url_description */ /* structure filled in with details */ /* of the string, or NULL if */ /* allocation failed. */ /*************************************************/ url_description * urlutils_return_description(const char * url_s) { url_description * new; if (!url_s || !*url_s) return NULL; /* Allocate the structure */ new = calloc(1, sizeof(url_description)); if (!new) return NULL; /* Find the item lengths */ if (_swix(URL_ParseURL, _INR(0,5), 0, URL_ParseURL_Reason_FindLengths, url_s, NULL, new, sizeof(url_description) / 4)) goto urlutils_return_description_free_and_exit; /* Expect the canonicalised form at the very least */ if (!new->full) goto urlutils_return_description_free_and_exit; new->full = malloc((int) new->full); if (!new->full) goto urlutils_return_description_free_and_exit; new->protocol = malloc((int) new->protocol); new->host = malloc((int) new->host); new->port = malloc((int) new->port); new->user = malloc((int) new->user); new->password = malloc((int) new->password); new->account = malloc((int) new->account); new->path = malloc((int) new->path); new->query = malloc((int) new->query); new->fragment = malloc((int) new->fragment); /* Fill in the block */ if (_swix(URL_ParseURL, _INR(0,5), 0, URL_ParseURL_Reason_FillBuffers, url_s, NULL, new, sizeof(url_description) / 4)) goto urlutils_return_description_free_and_exit; /* Finished */ return new; /* Error condition exit routine */ urlutils_return_description_free_and_exit: urlutils_free_description(new); return NULL; } /*************************************************/ /* urlutils_free_description() */ /* */ /* Frees a url_description and all memory */ /* associated with it. */ /* */ /* The function expects all filled in fields in */ /* the structure to point to malloced blocks, as */ /* this is the way that */ /* urlutils_return_description allocates it. */ /* */ /* Parameters: Pointer to a url_description */ /* structure. */ /*************************************************/ void urlutils_free_description(url_description * url_d) { /* Not the most demanding code in the world, really */ free(url_d->full); free(url_d->protocol); free(url_d->host); free(url_d->port); free(url_d->user); free(url_d->password); free(url_d->account); free(url_d->path); free(url_d->query); free(url_d->fragment); free(url_d); return; } /*************************************************/ /* urlutils_pathname_to_url() */ /* */ /* Takes a pathname, and turns it into a File */ /* URL, if it isn't one already. The pathname */ /* that you give is altered directly, so if you */ /* want to remember the path as well as the URL, */ /* ensure there is a second copy of it in */ /* another buffer somewhere. */ /* */ /* Parameters: Pointer to the pathname; */ /* */ /* Size of the buffer the pathname */ /* is stored in. */ /*************************************************/ void urlutils_pathname_to_url(char * path, int buffersize) { int len; char * pathdup; /* Try to expand the path - if this fails, carry on */ /* without the expansion. */ pathdup = malloc(strlen(path) + 1); if (pathdup) { unsigned int flags; strcpy(pathdup, path); /* Expand the path */ if ( _swix(OS_GSTrans, _INR(0,2) | _OUT(_FLAGS), pathdup, path, buffersize, &flags) || (flags & _C) ) { strcpy(path, pathdup); } else { /* Terminate the string at any control code */ for (len = 0; len < buffersize; len++) { if (path[len] < 32) { path[len] = 0; break; } } } free(pathdup); } /* Find the length of the File module protocol specifier */ len = strlen(FileMethod ProtocolSepShort); /* (urlutils.h) */ /* If the first part of the string doesn't match the FileMethod */ /* specifier (see URLutils.h) then insert this text and convert */ /* the rest of the path to a URL. */ if (strncmp(path, FileMethod ProtocolSepShort, len)) { memmove(path + len, path, buffersize - len); strncpy(path, FileMethod ProtocolSepShort, len); /* Ensure the string is terminated */ path[buffersize - 1] = 0; /* Now translate the pathname part of the URL to a Unix-style */ /* path scheme. */ urlutils_translate_pathname(path + len); } return; } /*************************************************/ /* urlutils_url_to_pathname() */ /* */ /* Takes a file:// URL, and turns it into a RISC */ /* OS pathname, if it isn't one already. The URL */ /* that you give is altered directly, so if you */ /* want to remember the URL as well as the new */ /* path, ensure there is a second copy of it in */ /* another buffer somewhere. */ /* */ /* Parameters: Pointer to the URL; */ /* */ /* Size of the buffer the URL is */ /* stored in. */ /*************************************************/ void urlutils_url_to_pathname(char * url, int buffersize) { url_description * url_d; url_d = urlutils_return_description(url); /* If this fails, try a more basic approach... */ if (!url_d) { int len; char * hash; /* Find the length of the File module protocol specifier */ len = strlen(FileMethod); /* (urlutils.h) */ /* If the first part of the string doesn't match the FileMethod */ /* specifier (see URLutils.h) then we can't do anything. */ if (!url || strncmp(url, FileMethod, len)) return; /* Copy over the file: specifier and any '/'s */ while (url[len] == '/') len++; memmove(url, url + len, buffersize - len); /* Strip off any fragment (this bit could fail badly for file */ /* system specifiers, but in the absence of URL_ParseURL */ /* working - 'url_d' is NULL if we reach here - there's not a */ /* lot of point working very hard to pull out. */ hash = strrchr(url, '#'); if (hash) *hash = 0; } else { /* We managed to get a full URL description, so take the */ /* path component of this. */ strncpy(url, url_d->path, buffersize - 1); url[buffersize - 1] = 0; urlutils_free_description(url_d); } /* Convert the path component of the URL back to RISC OS style */ urlutils_translate_pathname(url); return; } /*************************************************/ /* urlutils_translate_pathname() */ /* */ /* Takes a RISC OS-style pathname and turns it */ /* into a Unix-style pathname, or vice versa. */ /* */ /* The pathname you give is altered directly, so */ /* if you want to remember the path before */ /* translation, ensure there is a second copy of */ /* in another buffer somewhere. */ /* */ /* Parameters: Pointer to the pathname. */ /*************************************************/ void urlutils_translate_pathname(char * path) { char * p; p = path; /* Skip past any filing system separators (e.g. as in the */ /* colons in 'ADFS::<disc>.<path>'). */ while (*p && *p != ':') p++; /* Swap '/' for '.' */ while (*p) { if (*p == '/') *p = '.'; else if (*p == '.') *p = '/'; p++; } return; } /*************************************************/ /* urlutils_leafname_from_url() */ /* */ /* Returns a pointer to a string containing a */ /* possible leafname, based upon the URL passed */ /* into the function. */ /* */ /* Parameters: Pointer to a URL string; */ /* */ /* Pointer to a buffer into which to */ /* place the leafname (not the same */ /* as the URL string); */ /* */ /* Size of the buffer. */ /* */ /* Returns: Will fill the buffer in with some */ /* leafname, even if one could not */ /* be worked out from the URL. */ /* Returns the buffer pointer for */ /* convenience (even though the */ /* caller will almost certainly know */ /* this). */ /* */ /* Assumes: Neither pointer may be NULL. The */ /* buffer must be at least 2 bytes */ /* in size. If either condition is */ /* not met, NULL is returned and the */ /* buffer is left untouched. */ /*************************************************/ char * urlutils_leafname_from_url(char * url, char * leaf, int size) { int l = 0; if (!url || !leaf || size < 2) return NULL; memset(leaf, 0, size); /* l holds the string length if b->urlfdata exists */ l = (int) strlen(url); /* If the string exists and is not null, try to extract */ /* a leafname from it. */ if (l) { /* Set 'e' to point at the last character in the string, */ /* and we will use 's' to point to the first character */ /* after the host name. */ int e = l - 1; int s = 0; int found = 0; /* We want to do the following, bearing in mind that whilst */ /* a protocol at the start of the URL is assumed, it may be */ /* separated by nothing more than a colon (not even ':/' or */ /* '://'). The use of square brackets implies one or more */ /* analogous optional terms. */ /* */ /* a.b.c/[dir/]name.html -> name */ /* a.b.c/dir[/] -> dir */ /* a.b.c[/] -> Generic */ /* a.b.c/name.txt -> name */ /* a.b.c/name.tar.gz -> name/tar (as a consequence) */ /* a.b.c/name_1.2.1.gz -> name/1/2/1 (as a consequence) */ /* a.b.c/name.html#anc -> anc */ /* */ /* A slight change to the above behaviour is to only strip */ /* filename extensions if there is a defined filetype for */ /* that extension. Then, for example, we get the following. */ /* */ /* a.b.c/dir/name.txt -> name */ /* a.b.c/dir/name.zip -> name */ /* a.b.c/dir/name.01 -> name/01 */ /* a.b.c/dir/name.02 -> name/02 */ /* */ /* The tricky part is determining what bit is host name and */ /* what bit is path; it gets easier after that. First, look */ /* for a ':'. This will either be a protocol separator, or */ /* a port number separator. Trouble is, you need to skip */ /* any '/'s after the ':' if it's the first case, so check */ /* if any '.'s are passed when looking for the ':'. If so, */ /* we're on a port number. The only possible failure case */ /* is a URL with no protocol specified and a single word */ /* host name with a port number; but then, just about every */ /* other system will fail as the host name will be taken to */ /* be the protocol (e.g. 'dylan:8080'). So this isn't a */ /* problem, really - we'd return a generic response. */ while (s < l && url[s] != ':') { if (url[s] == '.') found = 1; s++; } /* Did we run out of string? If so, go back to the start; */ /* we may just have no protocol or port specified. */ if (s == l) s = 0; /* If we've not found any dots, may need to skip a few slashes; */ /* but not more than two, as three slashes (for example) implies */ /* that no host name is present. */ if (!found) { s++; /* Skip past the ':' */ if (url[s] == '/') s++; if (url[s] == '/') s++; /* If we ran out of string, must use a generic response */ if (s == l) goto return_generic; } /* We're either now on the ':' separating the host name */ /* and port number, or on the first character after any */ /* '/'s or the ':' separating the protocol from the */ /* host name. In either case, we now search forward for */ /* a single slash - the separator between host name and */ /* path. */ while (s < l && url[s] != '/') { s++; } /* Skip past the '/' */ if (url[s] == '/') s++; /* If we're run out string, go for a generic response - */ /* e.g. 'http://www/' or just 'http://www'. */ if (s >= l) goto return_generic; /* Otherwise, we can now start searching backwards for a */ /* usable leafname, knowing that reaching 's' is the */ /* exit condition. First, look for anchor names. */ if (strrchr(url, '#') > strrchr(url, '/')) /* Want 'a/b#c' -> 'c', but not 'a#b/c' -> 'b/c' */ { while (e > s && url[e] != '#') { e--; } /* Step forward past the '#' */ e++; /* If it turns out that the '#' is all that there is after */ /* the host name, it may be possible to step back and get */ /* whatever comes before it; or if we hit 's' in trying, */ /* we'll have to return a generic response. */ if (e == l) { e --; if (e <= s) goto return_generic; else goto get_directory_name; } /* Right, copy the string from this point forwards */ strncpy(leaf, url + e, size - 1); /* Finished, so jump to the final stripping routine */ goto strip_illegal_chars; } /* Right, if we have a trailing '/' or '#' (from the above code), */ /* following a directory name, then get that directory name. */ get_directory_name: if (url[e] == '/' || url[e] == '#') { int chars; found = e--; /* Find the start point of the name */ while (e > s && url[e] != '/') e--; /* If e is greater than s, we're sitting on the '/' */ /* found above, so advance past it. */ if (e > s) e++; /* Copy the name in */ chars = found - e; if (chars > size - 1) chars = size - 1; strncpy(leaf, url + e, chars); /* Finished - just need to take care of any illegal characters */ goto strip_illegal_chars; } /* Otherwise, continue, looking for a '/'. If a '.' is found on the */ /* way, remember the offset for the first time it is encountered. */ found = 0; while (e > s && url[e] != '/') { if (url[e] == '.' && !found) found = e; e--; } if (url[e] == '/') { e++; if (e >= l) goto return_generic; } /* We now have 'e' pointing to the start of a leafname */ /* and possibly 'found' pointing to the start of a */ /* filename extension. If the latter is true, check */ /* that there is something between the two... */ if (found && found - 1 == e) goto return_generic; /* OK, we have a string. If found is NULL, then we don't have a */ /* filename extension to strip */ if (!found) { strncpy(leaf, url + e, size - 1); } /* Otherwise, strip the extension if a filetype is found for it */ else { int chars = found - e; int filetype; /* Is there a filetype for this extension? */ if ( ( mimemap_extension_to_riscos(url + found, &filetype) || filetype == FileType_DATA ) && utils_strcasecmp(url + found, ".cgi") /* Special case '.cgi' - always strip it */ ) { /* Don't strip it */ strncpy(leaf, url + e, size - 1); } else { /* Strip the extension */ if (chars > size - 1) chars = size - 1; strncpy(leaf, url + e, chars); } } /* Right, that's the worst of it over...! The strip routine will */ /* take care of converting '.'s to '/'s, etc., if there are any. */ goto strip_illegal_chars; return_generic: lookup_token("NoURLleaf:Index",0,0); strncpy(leaf, tokens, size - 1); } /* There was apparently no URL in the buffer, so offer a */ /* neutral filename of HTMLfile. */ else { lookup_token("NoURLdata:HTMLfile",0,0); /* Will put the string in the 'tokens' global buffer */ strncpy(leaf, tokens, size - 1); } strip_illegal_chars: /* Scan the leaf for illegal characters */ l = 0; while (leaf[l]) { /* A few we can replace with meaningful alternatives */ if (leaf[l] == '.') leaf[l] = '/'; if (leaf[l] == '\\') leaf[l] = '/'; if (leaf[l] == '&') leaf[l] = '+'; if (leaf[l] == '"') leaf[l] = '\''; /* And the rest, replace with underscores */ if ( leaf[l] == '$' || leaf[l] == '%' || leaf[l] == '@' || leaf[l] == '^' || leaf[l] == ':' || leaf[l] == '#' || leaf[l] == '*' || leaf[l] == '"' || leaf[l] == '|' ) leaf[l] = '_'; l++; } /* Finished. */ return leaf; } /*************************************************/ /* urlutils_host_name_from_url() */ /* */ /* Extracts the host name from a given URL. */ /* */ /* Parameters: Pointer to the URL string; */ /* */ /* Pointer to a buffer to write the */ /* host name into; */ /* */ /* Size of the buffer. */ /*************************************************/ void urlutils_host_name_from_url(char * url, char * host, int size) { char * p; host[0] = 0; /* First look for '//', as in 'http://' */ p = strstr(url, ProtocolSeparator); if (p) { /* If found, copy everything after that into 'host' */ p += 2; strncpy(host, p, size - 1); host[size - 1] = 0; /* Now search for a '/', as in 'http://www.acorn/', */ /* and if found force a terminator there. */ p = strchr(host, '/'); if (p) *p = 0; } } /*************************************************/ /* urlutils_filetype_from_url() */ /* */ /* Examines a URL and returns a RISC OS filetype */ /* based on the filename extension in the URL. */ /* */ /* Parameters: Pointer to a null-terminated URL */ /* string. */ /* */ /* Returns: A RISC OS filetype. */ /*************************************************/ int urlutils_filetype_from_url(const char * url) { const char * dot; int filetype; if (!url || !*url) return NULL; dot = strrchr(url, '.'); if (!dot) return FileType_TEXT; if (mimemap_extension_to_riscos(dot, &filetype)) return FileType_TEXT; return filetype; // /* For now, hard code it. In future, use a mime mapper module. */ // // int len; // // if (!url || !*url) return NULL; // else len = strlen(url); // // /* Document types */ // // if (ExtensionMatches(url, len, ".html")) return FileType_HTML; // if (ExtensionMatches(url, len, ".htm")) return FileType_HTML; // if (ExtensionMatches(url, len, ".txt")) return FileType_TEXT; // if (ExtensionMatches(url, len, ".shtml")) return FileType_HTML; // if (ExtensionMatches(url, len, ".shtm")) return FileType_HTML; // if (ExtensionMatches(url, len, ".pdf")) return FileType_PDF; // if (ExtensionMatches(url, len, ".doc")) return FileType_WORD; // if (ExtensionMatches(url, len, ".ps")) return FileType_PS; // if (ExtensionMatches(url, len, ".eps")) return FileType_PS; // if (ExtensionMatches(url, len, ".wri")) return FileType_DOS; // if (ExtensionMatches(url, len, ".xls")) return FileType_XLS; // // /* Images */ // // if (ExtensionMatches(url, len, ".gif")) return FileType_GIF; // if (ExtensionMatches(url, len, ".jpg")) return FileType_JPEG; // if (ExtensionMatches(url, len, ".jpeg")) return FileType_JPEG; // if (ExtensionMatches(url, len, ".tiff")) return FileType_TIFF; // if (ExtensionMatches(url, len, ".tif")) return FileType_TIFF; // if (ExtensionMatches(url, len, ".png")) return FileType_PNG; // // /* Archives */ // // if (ExtensionMatches(url, len, ".zip")) return FileType_ARC; // if (ExtensionMatches(url, len, ".arc")) return FileType_ARC; // if (ExtensionMatches(url, len, ".spk")) return FileType_ARC; // if (ExtensionMatches(url, len, ".arj")) return FileType_ARC; // if (ExtensionMatches(url, len, ".gz")) return FileType_GZ; // if (ExtensionMatches(url, len, ".tar")) return FileType_ARC; // if (ExtensionMatches(url, len, ".zoo")) return FileType_ARC; // // /* Sounds */ // // if (ExtensionMatches(url, len, ".wav")) return FileType_WAVE; // if (ExtensionMatches(url, len, ".arm")) return FileType_ARMA; // if (ExtensionMatches(url, len, ".mod")) return FileType_MOD; // // /* Movies */ // // if (ExtensionMatches(url, len, ".mov")) return FileType_AVI; // if (ExtensionMatches(url, len, ".avi")) return FileType_AVI; // if (ExtensionMatches(url, len, ".qt")) return FileType_AVI; // if (ExtensionMatches(url, len, ".qtvr")) return FileType_AVI; // if (ExtensionMatches(url, len, ".rpl")) return FileType_ARMO; // if (ExtensionMatches(url, len, ".rep")) return FileType_ARMO; // // /* Miscellaneous */ // // if (ExtensionMatches(url, len, ".bin")) return FileType_DATA; // if (ExtensionMatches(url, len, ".dat")) return FileType_DATA; // if (ExtensionMatches(url, len, ".data")) return FileType_DATA; // if (ExtensionMatches(url, len, ".exe")) return FileType_DOS; // if (ExtensionMatches(url, len, ".com")) return FileType_DOS; // // /* Otherwise, return text */ // // return FileType_TEXT; } /*************************************************/ /* urlutils_create_hotlist_url() */ /* */ /* Creates a URL though which a hotlist file may */ /* be fetched. This is done by looking at a */ /* system variable '<App>$HotlistURL'. If that */ /* isn't set it looks at '<App>$HotlistURIFile' */ /* which can hold the path of a URI file to */ /* load. Lastly, it looks at the Choices file */ /* token 'HotlistPath', where a RISC OS pathname */ /* pointing to the file should be placed. This */ /* will be turned into a URL for fetching, so */ /* care must be taken over the path used. */ /* */ /* Parameters: Pointer to a buffer to place the */ /* URL in (not in a flex block!); */ /* */ /* Size of the buffer. */ /*************************************************/ void urlutils_create_hotlist_url(char * buffer, int size) { _kernel_oserror * e; char * varname; /* See if the variable exists. */ memset(buffer, 0, size); /* Equivalent to getenv, but the RISC OS implementation evaluates */ /* the system variable as an expression which we don't want; hence */ /* the direct use of the SWI. */ varname = lookup_token("_TaskName",1,0); strcat(varname, "$HotlistURL"); e = _swix(OS_ReadVarVal, _INR(0,4), varname, /* Variable name */ buffer, /* Buffer */ size, /* Buffer size, -1 to check it exists */ 0, /* Name pointer (0 for 1st call) */ 4); /* Variable type (4 = literal string) */ /* First lookup failed, so try the URI file. */ if (e) { varname = lookup_token("_TaskName",1,0); strcat(varname, "$HotlistURIFile"); e = _swix(OS_ReadVarVal, _INR(0,4), varname, buffer, size, 0, 4); if (e) { /* If the above gives an error, the variable doesn't exist; get */ /* the HotlistPath string from the Messages file instead. */ strncpy(buffer, lookup_choice("HotlistPath",1,0), size - 1); urlutils_pathname_to_url(buffer, size); } else { char path[Limits_OS_Pathname]; StrNCpy0(path, buffer); urlutils_load_uri_file(buffer, size, NULL, 0, path); } } } /*************************************************/ /* urlutils_create_home_url() */ /* */ /* Creates a URL though which a home page may be */ /* fetched. This is done by looking at a system */ /* variable '<App>$HomeURL'. If that isn't set, */ /* it looks at '<App>$HomeURIFile', which can� */ /* hold the path of a URI file to load. Lastly, */ /* it looks at the Choices file token */ /* 'HomePage'. */ /* */ /* Parameters: Pointer to a buffer to place the */ /* URL in (not in a flex block!); */ /* */ /* Size of the buffer. */ /*************************************************/ void urlutils_create_home_url(char * buffer, int size) { _kernel_oserror * e; char * varname; /* See if the variable exists */ memset(buffer, 0, size); /* Equivalent to getenv, but the RISC OS implementation evaluates */ /* the system variable as an expression which we don't want; hence */ /* the direct use of the SWI. */ varname = lookup_token("_TaskName",1,0); strcat(varname, "$HomeURL"); e = _swix(OS_ReadVarVal, _INR(0,4), varname, /* Variable name */ buffer, /* Buffer */ size, /* Buffer size, -1 to check it exists */ 0, /* Name pointer (0 for 1st call) */ 4); /* Variable type (4 = literal string) */ /* First lookup failed, so try the URI file. */ if (e) { varname = lookup_token("_TaskName",1,0); strcat(varname, "$HomeURIFile"); e = _swix(OS_ReadVarVal, _INR(0,4), varname, buffer, size, 0, 4); if (e) { /* If the above gives an error, the variable doesn't exist; get */ /* the HotlistPath string from the global choices structure */ /* instead. */ strncpy(buffer, choices.home_page, size - 1); } else { char path[Limits_OS_Pathname]; StrNCpy0(path, buffer); urlutils_load_uri_file(buffer, size, NULL, 0, path); } } } /*************************************************/ /* urlutils_fix_url() */ /* */ /* Takes a URL and 'fixes' it, e.g. appends a */ /* '/' character to a URL which is missing one. */ /* The contents of the buffer you give with the */ /* URL inside are altered directly, so if you */ /* want to remember the old URL, ensure there is */ /* a second copy of it in another buffer */ /* somewhere. */ /* */ /* Parameters: Pointer to the URL; */ /* */ /* Size of the buffer the URL is */ /* stored in. */ /* */ /* Returns: Pointer to the fixed URL (which */ /* at the moment is the buffer that */ /* you passed in). */ /*************************************************/ char * urlutils_fix_url(char * buffer, int buffersize) { int len, shl; int flen, fshl; int glen, gshl; int blen, plen; plen = strlen(ProtocolSeparator); shl = strlen(HTTPmethod); len = shl + plen; fshl = strlen(FTPmethod); flen = fshl + plen; gshl = strlen(GopherMethod); glen = gshl + plen; blen = strlen(buffer); /* If there's no ':' in the string, insert a protocol type */ if ( !strchr(buffer, ':') && blen + len < buffersize && blen + flen < buffersize ) { /* If the site appears to be an FTP site, insert the FTP protocol */ /* at the start. Similarly for Gopher; else insert HTTP. */ if (!strncmp(buffer, FTPmethod, fshl - 1)) /* -1 as we don't want to compare the ':' */ { memmove(buffer + flen, buffer, buffersize - flen); strncpy(buffer, FTPmethod ProtocolSeparator, flen); } else if (!strncmp(buffer, GopherMethod, gshl - 1)) { memmove(buffer + glen, buffer, buffersize - glen); strncpy(buffer, GopherMethod ProtocolSeparator, glen); } else { memmove(buffer + len, buffer, buffersize - len); strncpy(buffer, HTTPmethod ProtocolSeparator, len); } buffer[buffersize - 1] = 0; } /* If there are at least 2 unused bytes in the buffer, and the */ /* front of the string matches the HTTPMethod specifier (again */ /* this is defined at the top of this file) then search for a */ /* '/' character which isn't part of a '//' sequence. If none */ /* is found, append a '/'. This is why 2 bytes free are needed */ /* - one for the '/', one for the string terminator. */ if (strlen(buffer) < buffersize - 2 && !strncmp(buffer, HTTPmethod, shl)) { int i, s = 0; for (i = 0; !s && buffer[i] && (i < (buffersize - 1)); i ++) { /* If we have a '/' but not a '//' sequence, mark this with s = 1 */ if (buffer[i] == '/' && buffer[i + 1] != '/') s = 1; /* If at start of a '//' sequence, skip past it */ else if (buffer[i] == '/') i++; } if (!s) strcat(buffer,"/"); } return buffer; } /*************************************************/ /* urlutils_load_uri_file() */ /* */ /* Loads a URI file. Will take ANT URL files */ /* too. The given buffer will be filled with a */ /* null-terminated URI from the file. */ /* */ /* The load terminates when the buffer is full */ /* except for the last byte (to allow for a */ /* forced terminator), or a control code is met */ /* in the URI file. Note that the buffer is */ /* initialised to hold null bytes before the URI */ /* file is opened. */ /* */ /* For URI files, you may also try to read a */ /* title string. */ /* */ /* If there is an error opening the file or the */ /* file is empty, the contents of the buffer are */ /* undefined. */ /* */ /* Parameters: Pointer to the buffer for the */ /* URL; */ /* */ /* Size of the buffer; */ /* */ /* Pointer to the buffer for the */ /* title (if any), or NULL; */ /* */ /* Size of the buffer (or zero); */ /* */ /* Pointer to the pathname of the */ /* URI file. */ /* */ /* Assumes: The buffers and path must NOT be */ /* the same area in memory. */ /*************************************************/ void urlutils_load_uri_file(char * buffer, size_t size, char * tbuffer, size_t tsize, char * path) { FILE * fp; int byte, counter; int type, found; /* Warning - heavy use of 'goto's coming up shortly...! */ if (!size) return; memset(buffer, 0, size); if (tbuffer && tsize) memset(tbuffer, 0, tsize); /* Does the file exist? */ if ( _swix(OS_File, _INR(0,1) | _OUT(0) | _OUT(6), 23, /* Read catalogue info for named, stamped object */ path, &found, &type) ) return; /* 'found' should be 1 (a file, rather than not found, a directory, etc.). */ if (found != 1) return; /* Open the file */ fp = fopen(path, "rb"); if (fp) { byte = getc(fp); /* For URL files, go straight to URL reading - they're just */ /* a terminated, or unterminated URL in a file. */ if (type != FileType_URI) goto urlutils_load_uri_file_read_uri; /* If it is a URI file, it must start with 'URI'. */ if (byte != 'U') goto urlutils_load_uri_file_not_a_uri_file; byte = getc(fp); if (byte != 'R') goto urlutils_load_uri_file_not_a_uri_file; byte = getc(fp); if (byte != 'I') goto urlutils_load_uri_file_not_a_uri_file; /* Get to first character after the 'I' */ byte = getc(fp); /* Now find the version number - skip white space */ urlutils_load_uri_file_skip_white_space_1: while (byte != EOF && byte < ' ') byte = getc(fp); /* If we've hit a hash, this is a comment line - terminated by white */ /* space or end of file. */ if (byte == '#') { /* Now want to *find* the white space to skip the comment */ while (byte != EOF && byte >= ' ') byte = getc(fp); /* If we're not at the end of the file, loop back and continue */ /* skipping white space. */ if (byte != EOF) goto urlutils_load_uri_file_skip_white_space_1; } /* By now, we're either at EOF or the start of the first real entry */ /* after 'URL', which will be the file version. URI file versions */ /* are guaranteed backwards compatible, so we can skip this bit. */ while (byte != EOF && byte >= ' ') byte = getc(fp); /* Now we want to get to the URI, so again, skip white space */ /* and comment lines. After that, we'll be on the first byte */ /* of the URI (or end of file, if it's broken). */ urlutils_load_uri_file_skip_white_space_2: while (byte != EOF && byte < ' ') byte = getc(fp); if (byte == '#') { while (byte != EOF && byte >= ' ') byte = getc(fp); if (byte != EOF) goto urlutils_load_uri_file_skip_white_space_2; } /* Load the URI component - assume everything from here up */ /* to any control chracter or EOF is part of the URI. Note */ /* that 'byte' already contains the first character. */ urlutils_load_uri_file_read_uri: counter = 0; while (byte != EOF && byte >= ' ' && counter < size - 1) { buffer[counter++] = byte; byte = getc(fp); } /* If it's a single '*', the URI is not present */ if (!strcmp(buffer, "*")) *buffer = 0; /* We may still have a title to read... */ if (type == FileType_URI && tbuffer && tsize) { /* Once more, skip any white space or comments */ urlutils_load_uri_file_skip_white_space_3: while (byte != EOF && byte < ' ') byte = getc(fp); if (byte == '#') { while (byte != EOF && byte >= ' ') byte = getc(fp); if (byte != EOF) goto urlutils_load_uri_file_skip_white_space_3; } /* Now read the title */ counter = 0; while (byte != EOF && byte >= ' ' && counter < size - 1) { tbuffer[counter++] = byte; byte = getc(fp); } /* If it's a single '*', the URI is not present */ if (!strcmp(tbuffer, "*")) *tbuffer = 0; } fclose(fp); } return; /* Error condition exits */ urlutils_load_uri_file_not_a_uri_file: /* Not a URI / URL file */ if (fp) fclose(fp); erb.errnum = Utils_Error_Custom_Message; StrNCpy0(erb.errmess, lookup_token("NotAURI:This is not a valid URI file.", 0, 0)); show_error_ret(&erb); return; } /*************************************************/ /* urlutils_extract_uri() */ /* */ /* Looks at a URI file loaded into a buffer, and */ /* overwrites it with the URL contents extracted */ /* from the body. */ /* */ /* Parameters: Pointer to the buffer holding the */ /* URI file; */ /* */ /* Size of the file (the buffer is */ /* assumed to be at least this size */ /* but not assumed to be larger). */ /* */ /* Returns: Contents of the buffer are */ /* updated to hold a null terminated */ /* URI followed by a null terminated */ /* title string, if there is one. */ /*************************************************/ void urlutils_extract_uri(char * buffer, size_t file_size) { int copy = 0; int counter = 0; int is_uri = 1; if (!buffer || !file_size) return; /* Ensure it starts with 'URI' - if not, jump straight to */ /* URI extraction (assume it's a URL file). */ if (strncmp(buffer, "URI", 3)) { is_uri = 0; goto urlutils_extract_uri_read_uri; } /* Point to the first byte after the 'URI' indentifier */ counter = 3; /* Skip white space to find the version number */ urlutils_extract_uri_skip_white_space_1: while ( counter < file_size && buffer[counter] && buffer[counter] < ' ' ) counter++; /* If we find a comment, skip the comment body */ if (buffer[counter] == '#') { while ( counter < file_size && buffer[counter] && buffer[counter] >= ' ' ) counter++; /* Now go back to skip the white space after the comment, and */ /* thus any other comments that follow. */ if (buffer[counter]) goto urlutils_extract_uri_skip_white_space_1; } /* Skip the file version */ while ( counter < file_size && buffer[counter] && buffer[counter] >= ' ' ) counter++; /* Again, skip white space and comments */ urlutils_extract_uri_skip_white_space_2: while ( counter < file_size && buffer[counter] && buffer[counter] < ' ' ) counter++; if (buffer[counter] == '#') { while ( counter < file_size && buffer[counter] && buffer[counter] >= ' ' ) counter++; if (buffer[counter]) goto urlutils_extract_uri_skip_white_space_2; } urlutils_extract_uri_read_uri: /* Now we're at the URI. Copy it to the start of the buffer. */ while ( counter < file_size && buffer[counter] && buffer[counter] >= ' ' ) buffer[copy++] = buffer[counter++]; /* Need to make sure that the string is terminated - if we're */ /* likely to overflow the buffer, we must overwrite the last */ /* char with a terminator. You never know, it could be a non- */ /* essential last character (e.g. trailing '/'). */ if (copy && copy < file_size) buffer[copy] = 0, copy++; else buffer[copy - 1] = 0; /* May have a title to read, too. */ if (is_uri) { /* Skip white space and comments once more */ urlutils_extract_uri_skip_white_space_3: while ( counter < file_size && buffer[counter] && buffer[counter] < ' ' ) counter++; if (buffer[counter] == '#') { while ( counter < file_size && buffer[counter] && buffer[counter] >= ' ' ) counter++; if (buffer[counter]) goto urlutils_extract_uri_skip_white_space_3; } /* Now read the title */ while ( counter < file_size && buffer[counter] && buffer[counter] >= ' ' ) buffer[copy++] = buffer[counter++]; /* Again, ensure things are correctly terminated */ if (copy && copy < file_size) buffer[copy] = 0; else buffer[copy - 1] = 0; } /* If we've ended up with just a single star, the field is blank */ if (!strcmp(buffer, "*")) *buffer = 0; return; } /*************************************************/ /* urlutils_internal_extra() */ /* */ /* Returns an offset into a given string at */ /* which extra data in an internal URL may be */ /* found. */ /* */ /* Parameters: Pointer to the URL string. */ /* */ /* Returns: Offset for the extra data, or 0 */ /* if none is found. */ /*************************************************/ int urlutils_internal_extra(char * iurl) { char * extra; if (strncmp(iurl, Internal_URL, Int_URL_Len)) return 0; extra = strchr(iurl, ':'); if (!extra) return 0; else extra ++; return (int) (extra - iurl); } /*************************************************/ /* urlutils_internal_tail() */ /* */ /* Returns an offset into a given string at */ /* which tail data (typically a URL leafname) */ /* may be found. */ /* */ /* Parameters: Pointer to the URL string. */ /* */ /* Returns: Offset for the tail data, or 0 if */ /* none is found. */ /*************************************************/ int urlutils_internal_tail(char * iurl) { char * tail, * extra; int exoff, found = 0; exoff = urlutils_internal_extra(iurl); if (!exoff) return 0; extra = iurl + exoff; tail = iurl + strlen(iurl); /* No '-1' here as tail is decremented early in the while loop below */ while (tail > extra && !found) { tail--; if (*tail == '/') found = 1; } if (!found) return 0; else tail ++; return (int) (tail - iurl); } /*************************************************/ /* urlutils_set_displayed() */ /* */ /* On the basis of a given internal URL, sets */ /* the 'displayed' field of a given browser_data */ /* structure. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* that is to be altered; */ /* */ /* Pointer to the internal URL. */ /*************************************************/ void urlutils_set_displayed(browser_data * b, char * iurl) { if (!strncmp(iurl, Internal_URL, Int_URL_Len)) { if (!strncmp(iurl + Int_URL_Len, ForExternalHImage, strlen(ForExternalHImage))) b->displayed = Display_External_Image; else if (!strncmp(iurl + Int_URL_Len, ForExternalNImage, strlen(ForExternalNImage))) b->displayed = Display_External_Image; else if (!strncmp(iurl + Int_URL_Len, ForScrapFile, strlen(ForScrapFile))) b->displayed = Display_Scrap_File; else if (!strncmp(iurl + Int_URL_Len, ForGoBack, strlen(ForGoBack))) b->displayed = Display_Previous_Page; else if (!strncmp(iurl + Int_URL_Len, ForGoForward, strlen(ForGoForward))) b->displayed = Display_Next_Page; else if (!strncmp(iurl + Int_URL_Len, ForGoRecover, strlen(ForGoRecover))) b->displayed = Display_Recovered_Page; else if (!strncmp(iurl + Int_URL_Len, ForGoReload, strlen(ForGoReload))) b->displayed = Display_Reloaded_Page; else if (!strncmp(iurl + Int_URL_Len, ForGoHome, strlen(ForGoHome))) b->displayed = Display_Home_Page; else if (!strncmp(iurl + Int_URL_Len, ForAbout, strlen(ForAbout))) b->displayed = Display_About_Page; else if (!strncmp(iurl + Int_URL_Len, ForGoToURL, strlen(ForGoToURL))) b->displayed = Display_Embedded_URL; else if (!strncmp(iurl + Int_URL_Len, ForAnError, strlen(ForAnError))) b->displayed = Display_Embedded_Error; else b->displayed = Display_Fetched_Page; } else b->displayed = Display_Fetched_Page; } /*************************************************/ /* urlutils_check_protocols() */ /* */ /* Checks a given URL to see if the fetch */ /* protocol it specifies can be handled. */ /* */ /* Parameters: Pointer to the URL string. */ /* */ /* Returns: 1 if the URL can be handled (i.e. */ /* the protocol at the start of the */ /* URL matches one that the Messages */ /* file says a module which is */ /* currently running copes with), */ /* else 0. */ /*************************************************/ int urlutils_check_protocols(char * url) { int protocols = 0; int i; char p[24]; if (!url || (url && !*url)) return 0; /* Find the number of possible protocols */ protocols = atoi(lookup_control("ProtocolMax", 1, NULL)); /* Exit if not found / not a sensible number */ if (protocols <= 0) return 0; /* Loop round all protocols */ for (i = 1; i <= protocols; i++) { /* Look up the module name by building a MessageTrans */ /* token of the appropriate format, and call OS_Module */ /* 18 (lookup module) for it; if the SWI doesn't */ /* raise an error, the module was found. */ sprintf(p, "ProtocolM%d", i); if (!_swix(OS_Module, _INR(0,1), 18, lookup_control(p, 1, NULL))) { /* Module is present, so check the protocol */ sprintf(p, "ProtocolU%d", i); lookup_control(p, 1, NULL); /* If the protocol identifier can be found... */ if (tokens[0] != '!') { /* Compare it to the same number of characters in */ /* the given URL. If it matches, we can deal with */ /* the URL. */ if (!utils_strncasecmp(tokens, url, strlen(tokens))) return 1; /* Otherwise, loop on to the next protocol... */ } } } /* If we reach here, no protocol was found. */ return 0; } /*************************************************/ /* urlutils_cycle_protocol() */ /* */ /* Given a URL, add in the HTTP protocol */ /* specifier if none is already present, or */ /* cycle through those in order of appearance in */ /* the protocols list in Controls. */ /* */ /* Parameters: Pointer to the URL string; */ /* */ /* Size of the buffer the URL string */ /* lies in (the string will be */ /* updated). */ /* */ /* Returns: 1 if the URL was changed, else 0. */ /*************************************************/ int urlutils_cycle_protocol(char * url, int size) { int protocols = 0; int in_use = 0; int have_any = 0; int have_one = 0; int i, ulen, plen; char p[24]; if (!url || !size) return 0; /* Find the number of possible protocols */ protocols = atoi(lookup_control("ProtocolMax", 1, NULL)); /* Exit if not found / not a sensible number */ if (protocols <= 0) return 0; /* Loop round all protocols */ for (i = 1; i <= protocols; i++) { /* Look up the module name by building a MessageTrans */ /* token of the appropriate format, and call OS_Module */ /* 18 (lookup module) for it; if the SWI doesn't */ /* raise an error, the module was found. */ sprintf(p, "ProtocolM%d", i); if (!_swix(OS_Module, _INR(0,1), 18, lookup_control(p, 1, NULL))) { /* Module is present, so check the protocol */ sprintf(p, "ProtocolU%d", i); lookup_control(p, 1, NULL); /* If the protocol identifier can be found... */ if (tokens[0] != '!') { have_any = 1; /* Compare it to the same number of characters in */ /* the given URL. If it matches, flag this. */ if (!strncmp(tokens, url, strlen(tokens))) { in_use = i, have_one = 1; break; } /* Otherwise, loop on to the next protocol... */ } } } /* If we haven't got any available protocols (!) exit */ if (!have_any) return 0; /* Get rid of any existing protocol... */ if (have_one) { char * separator = (char *) (((int) url) + strlen(tokens)); memmove(url, separator, strlen(url) - (((int) separator) - ((int) url)) + 1); } /* Find the first/next protocol */ have_any = 0; while (!have_any) { /* If nothing was found in the first loop (the URL doesn't */ /* specify a protocol, or it wasn't recognised) then in_use */ /* starts at 0; we thus increment to 1, which is what we */ /* want. So there's no special casing needed here. */ in_use ++; if (in_use > protocols) in_use = 1; /* Again, see if the protocol is available */ sprintf(p, "ProtocolM%d", in_use); if (!_swix(OS_Module, _INR(0,1), 18, lookup_control(p, 1, NULL))) { /* Module is present, so check the protocol */ sprintf(p, "ProtocolU%d", in_use); lookup_control(p, 1, NULL); /* If the protocol identifier can be found, flag it */ if (tokens[0] != '!') have_any = 1; } } /* Insert the new protocol */ ulen = strlen(url); plen = strlen(tokens); /* (The protocol) */ if (ulen + plen + 1 > size) return have_one; /* Yikes, if it won't fit we may have thrown out an existing protocol... */ memmove(url + plen, url, ulen + 1); strncpy(url, tokens, plen); /* Finished */ return 1; } /*************************************************/ /* urlutils_dispatch() */ /* */ /* Puts a given URI into the URI queue and sends */ /* it out to the URI handler. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* for which the URI relates; */ /* */ /* Pointer to null-terminated URI */ /* string (not in a movable block, */ /* so not, e.g., in a flex block); */ /* */ /* URI queue flags (see URIutils.h). */ /* */ /* Assumes: That the caller has already made */ /* sure the URI handler is present. */ /*************************************************/ _kernel_oserror * urlutils_dispatch(browser_data * b, char * uri, unsigned int flags) { _kernel_oserror * e; unsigned int return_code; uri_queue * entry; #ifdef TRACE if (tl & (1u<<21)) Printf("urlutils_dispatch: Called for %p with '%s'\n",b,uri); #endif /* Claim memory for the new entry */ entry = malloc(sizeof(uri_queue)); /* Moan if the claim failed */ if (!entry) { #ifdef TRACE if (tl & (1u<<21)) Printf("urlutils_dispatch: Memory claim for queue entry failed\n",b,uri); #endif return make_no_fetch_memory_error(15); } #ifdef TRACE malloccount += sizeof(uri_queue); if (tl & (1u<<13)) Printf("** malloccount (urlutils_dispatch): \0211%d\0217\n",malloccount); if (tl & (1u<<21)) Printf("urlutils_dispatch: Claimed queue entry %p\n",entry); #endif /* Fill in part of the entry */ entry->flags = flags; entry->b = b; /* If there are no entries, set uri_queue_base to the */ /* address of this one. Otherwise, point this entry's */ /* 'next' to the current base item, and point that */ /* item's 'prev' back to this entry. Then replace the */ /* current base entry with this new one. */ entry->prev = NULL; if (!uri_queue_base) entry->next = NULL; else { entry->next = uri_queue_base; uri_queue_base->prev = entry; } uri_queue_base = entry; /* Now call the URI handler and get a handle to fill in */ /* the last uri_queue field. */ e = uri_dispatch(URI_Dispatch_Inform, uri, task_handle, &return_code, NULL, &entry->uri_handle); if (e) { #ifdef TRACE if (tl & (1u<<21)) Printf("urlutils_dispatch: Exitting with error\n"); #endif return e; } /* If the request was refused complain */ if (return_code != URI_Dispatch_RequestAccepted) { erb.errnum = Utils_Error_Custom_Message; StrNCpy0(erb.errmess, lookup_token("Refused:Cannot fetch this address as the fetch request was refused by the internal handler.", 0,0)); #ifdef TRACE if (tl & (1u<<21)) Printf("urlutils_dispatch: Exitting with error\n"); #endif return &erb; } /* Otherwise exit successfully */ #ifdef TRACE if (tl & (1u<<21)) Printf("urlutils_dispatch: Successful\n"); #endif return NULL; } /*************************************************/ /* urlutils_remove_from_queue() */ /* */ /* Removes a specified entry from the list of */ /* uri_queue structures, freeing the memory */ /* allocated for it. */ /* */ /* Parameters: The URI handle of the entry. */ /*************************************************/ _kernel_oserror * urlutils_remove_from_queue(URI_handle_t uri_handle) { uri_queue * entry = uri_queue_base; #ifdef TRACE if (tl & (1u<<21)) Printf("urlutils_remove_from_queue: Called with handle %p\n", uri_handle); #endif /* Try to find the entry */ while (entry && entry->uri_handle != uri_handle) entry = entry->next; #ifdef TRACE /* Complain if not found */ if (!entry) { erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Can't find URI handle %p in URI queue", uri_handle); if (tl & (1u<<21)) Printf("urlutils_remove_from_queue: Exitting with error\n"); return &erb; } #else /* Fail silently */ if (!entry) return NULL; #endif if (entry->prev) entry->prev->next = entry->next; if (entry->next) entry->next->prev = entry->prev; if (entry == uri_queue_base) uri_queue_base = entry->next; #ifdef TRACE malloccount -= sizeof(uri_queue); if (tl & (1u<<13)) Printf("** malloccount (uriutils_remove_from_queue): \0212%d\0217\n",malloccount); if (tl & (1u<<21)) Printf("urlutils_remove_from_queue: Freeing entry %p\n",entry); #endif free (entry); #ifdef TRACE if (tl & (1u<<21)) Printf("urlutils_remove_from_queue: Successful\n"); #endif return NULL; } /*************************************************/ /* urlutils_find_queue_entry() */ /* */ /* Finds an entry in the list of uri_queue */ /* structures. */ /* */ /* Parameters: The URI handle of the entry. */ /* */ /* Returns: Pointer to the entry, or NULL if */ /* no entry with that handle could */ /* be found. */ /*************************************************/ uri_queue * urlutils_find_queue_entry(URI_handle_t uri_handle) { uri_queue * entry = uri_queue_base; #ifdef TRACE if (tl & (1u<<21)) Printf("urlutils_find_queue_entry: Called with handle %p\n", uri_handle); #endif while (entry && entry->uri_handle != uri_handle) entry = entry->next; #ifdef TRACE if (tl & (1u<<21)) Printf("urlutils_find_queue_entry: Returning with entry %p\n", entry); #endif return entry; }