1.\"- 2.\" Copyright (c) 1998-2004 Dag-Erling Co�dan Sm�rgrav 3.\" All rights reserved. 4.\" 5.\" Redistribution and use in source and binary forms, with or without 6.\" modification, are permitted provided that the following conditions 7.\" are met: 8.\" 1. Redistributions of source code must retain the above copyright 9.\" notice, this list of conditions and the following disclaimer. 10.\" 2. Redistributions in binary form must reproduce the above copyright 11.\" notice, this list of conditions and the following disclaimer in the 12.\" documentation and/or other materials provided with the distribution. 13.\" 14.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24.\" SUCH DAMAGE. 25.\" 26.\" $FreeBSD: fetch.3,v 1.64 2007/12/18 11:03:26 des Exp $ 27.\" $NetBSD: fetch.3,v 1.1.1.6 2009/04/04 23:26:04 joerg Exp $ 28.\" 29.Dd February 4, 2009 30.Dt FETCH 3 31.Os 32.Sh NAME 33.Nm fetchMakeURL , 34.Nm fetchParseURL , 35.Nm fetchCopyURL , 36.Nm fetchFreeURL , 37.Nm fetchXGetURL , 38.Nm fetchGetURL , 39.Nm fetchPutURL , 40.Nm fetchStatURL , 41.Nm fetchListURL , 42.Nm fetchXGet , 43.Nm fetchGet , 44.Nm fetchPut , 45.Nm fetchStat , 46.Nm fetchList , 47.Nm fetchXGetFile , 48.Nm fetchGetFile , 49.Nm fetchPutFile , 50.Nm fetchStatFile , 51.Nm fetchListFile , 52.Nm fetchXGetHTTP , 53.Nm fetchGetHTTP , 54.Nm fetchPutHTTP , 55.Nm fetchStatHTTP , 56.Nm fetchListHTTP , 57.Nm fetchXGetFTP , 58.Nm fetchGetFTP , 59.Nm fetchPutFTP , 60.Nm fetchStatFTP , 61.Nm fetchListFTP 62.Nm fetchInitURLList , 63.Nm fetchFreeURLList , 64.Nm fetchUnquotePath , 65.Nm fetchUnquoteFilename , 66.Nm fetchStringifyURL , 67.Nm fetch 68.Nd file transfer functions 69.Sh LIBRARY 70.Lb libfetch 71.Sh SYNOPSIS 72.In stdio.h 73.In fetch.h 74.Ft struct url * 75.Fn fetchMakeURL "const char *scheme" "const char *host" "int port" "const char *doc" "const char *user" "const char *pwd" 76.Ft struct url * 77.Fn fetchParseURL "const char *URL" 78.Ft struct url * 79.Fn fetchCopyURL "const struct url *u" 80.Ft void 81.Fn fetchFreeURL "struct url *u" 82.Ft fetchIO * 83.Fn fetchXGetURL "const char *URL" "struct url_stat *us" "const char *flags" 84.Ft fetchIO * 85.Fn fetchGetURL "const char *URL" "const char *flags" 86.Ft fetchIO * 87.Fn fetchPutURL "const char *URL" "const char *flags" 88.Ft int 89.Fn fetchStatURL "const char *URL" "struct url_stat *us" "const char *flags" 90.Ft int 91.Fn fetchListURL "struct url_list *list" "const char *URL" "const char *flags" 92.Ft fetchIO * 93.Fn fetchXGet "struct url *u" "struct url_stat *us" "const char *flags" 94.Ft fetchIO * 95.Fn fetchGet "struct url *u" "const char *flags" 96.Ft fetchIO * 97.Fn fetchPut "struct url *u" "const char *flags" 98.Ft int 99.Fn fetchStat "struct url *u" "struct url_stat *us" "const char *flags" 100.Ft int 101.Fn fetchList "struct url_list *list" "struct url *u" "const char *flags" 102.Ft fetchIO * 103.Fn fetchXGetFile "struct url *u" "struct url_stat *us" "const char *flags" 104.Ft fetchIO * 105.Fn fetchGetFile "struct url *u" "const char *flags" 106.Ft fetchIO * 107.Fn fetchPutFile "struct url *u" "const char *flags" 108.Ft int 109.Fn fetchStatFile "struct url *u" "struct url_stat *us" "const char *flags" 110.Ft int 111.Fn fetchListFile "struct url_list *list" "struct url *u" "const char *flags" 112.Ft fetchIO * 113.Fn fetchXGetHTTP "struct url *u" "struct url_stat *us" "const char *flags" 114.Ft fetchIO * 115.Fn fetchGetHTTP "struct url *u" "const char *flags" 116.Ft fetchIO * 117.Fn fetchPutHTTP "struct url *u" "const char *flags" 118.Ft int 119.Fn fetchStatHTTP "struct url *u" "struct url_stat *us" "const char *flags" 120.Ft int 121.Fn fetchListHTTP "struct url_list *list" "struct url *u" "const char *flags" 122.Ft fetchIO * 123.Fn fetchXGetFTP "struct url *u" "struct url_stat *us" "const char *flags" 124.Ft fetchIO * 125.Fn fetchGetFTP "struct url *u" "const char *flags" 126.Ft fetchIO * 127.Fn fetchPutFTP "struct url *u" "const char *flags" 128.Ft int 129.Fn fetchStatFTP "struct url *u" "struct url_stat *us" "const char *flags" 130.Ft int 131.Fn fetchListFTP "struct url_list *list" "struct url *u" "const char *flags" 132.Ft void 133.Fn fetchInitURLList "struct url_list *ul" 134.Ft void 135.Fn fetchFreeURLList "struct url_list *ul" 136.Ft char * 137.Fn fetchUnquotePath "struct url *u" 138.Ft char * 139.Fn fetchUnquoteFilename "struct url *u" 140.Ft char * 141.Fn fetchStringifyURL "const struct url *u" 142.Sh DESCRIPTION 143These functions implement a high-level library for retrieving and 144uploading files using Uniform Resource Locators (URLs). 145.Pp 146.Fn fetchParseURL 147takes a URL in the form of a null-terminated string and splits it into 148its components function according to the Common Internet Scheme Syntax 149detailed in RFC 1738. 150A regular expression which produces this syntax is: 151.Bd -literal -offset indent 152\*[Lt]scheme\*[Gt]:(//(\*[Lt]user\*[Gt](:\*[Lt]pwd\*[Gt])?@)?\*[Lt]host\*[Gt](:\*[Lt]port\*[Gt])?)?/(\*[Lt]document\*[Gt])? 153.Ed 154.Pp 155If the URL does not seem to begin with a scheme name, it is assumed to be a local path. 156Only absolute path names are accepted. 157.Pp 158Note that some components of the URL are not necessarily relevant to 159all URL schemes. 160For instance, the file scheme only needs the 161.Aq scheme 162and 163.Aq document 164components. 165.Fn fetchParseURL 166quotes any unsafe character in the URL automatically. 167This is not done by 168.Fn fetchMakeURL . 169.Fn fetchCopyURL 170copies an existing 171.Vt url 172structure. 173.Pp 174.Fn fetchMakeURL , 175.Fn fetchParseURL , 176and 177.Fn fetchCopyURL 178return a pointer to a 179.Vt url 180structure, which is defined as follows in 181.In fetch.h : 182.Bd -literal 183#define URL_SCHEMELEN 16 184#define URL_USERLEN 256 185#define URL_PWDLEN 256 186#define URL_HOSTLEN 255 187 188struct url { 189 char scheme[URL_SCHEMELEN + 1]; 190 char user[URL_USERLEN + 1]; 191 char pwd[URL_PWDLEN + 1]; 192 char host[URL_HOSTLEN + 1]; 193 int port; 194 char *doc; 195 off_t offset; 196 size_t length; 197 time_t last_modified; 198}; 199.Ed 200.Pp 201The pointer returned by 202.Fn fetchMakeURL , 203.Fn fetchCopyURL , 204and 205.Fn fetchParseURL 206should be freed using 207.Fn fetchFreeURL . 208The size of 209.Vt struct URL 210is not part of the ABI. 211.Pp 212.Fn fetchXGetURL , 213.Fn fetchGetURL , 214and 215.Fn fetchPutURL 216constitute the recommended interface to the 217.Nm fetch 218library. 219They examine the URL passed to them to determine the transfer 220method, and call the appropriate lower-level functions to perform the 221actual transfer. 222.Fn fetchXGetURL 223also returns the remote document's metadata in the 224.Vt url_stat 225structure pointed to by the 226.Fa us 227argument. 228.Pp 229The 230.Fa flags 231argument is a string of characters which specify transfer options. 232The 233meaning of the individual flags is scheme-dependent, and is detailed 234in the appropriate section below. 235.Pp 236.Fn fetchStatURL 237attempts to obtain the requested document's metadata and fill in the 238structure pointed to by its second argument. 239The 240.Vt url_stat 241structure is defined as follows in 242.In fetch.h : 243.Bd -literal 244struct url_stat { 245 off_t size; 246 time_t atime; 247 time_t mtime; 248}; 249.Ed 250.Pp 251If the size could not be obtained from the server, the 252.Fa size 253field is set to \-1. 254If the modification time could not be obtained from the server, the 255.Fa mtime 256field is set to the epoch. 257If the access time could not be obtained from the server, the 258.Fa atime 259field is set to the modification time. 260.Pp 261.Fn fetchListURL 262attempts to list the contents of the directory pointed to by the URL provided. 263The pattern can be a simple glob-like expression as hint. 264Callers should not depend on the server to filter names. 265If successful, it appends the list of entries to the 266.Vt url_list 267structure. 268The 269.Vt url_list 270structure is defined as follows in 271.In fetch.h : 272.Bd -literal 273struct url_list { 274 size_t length; 275 size_t alloc_size; 276 struct url *urls; 277}; 278.Ed 279.Pp 280The list should be initialized by calling 281.Fn fetchInitURLList 282and the entries be freed by calling 283.Fn fetchFreeURLList . 284.Pp 285.Fn fetchStringifyURL 286returns the URL as string. 287.Fn fetchUnquotePath 288returns the path name part of the URL with any quoting undone. 289Query arguments and fragment identifiers are not included. 290.Fn fetchUnquoteFilename 291returns the last component of the path name as returned by 292.Fn fetchUnquotePath . 293.Fn fetchStringifyURL , 294.Fn fetchUnquotePath , 295and 296.Fn fetchUnquoteFilename 297return a string that should be deallocated with 298.Fn free 299after use. 300.Pp 301.Fn fetchXGet , 302.Fn fetchGet , 303.Fn fetchPut , 304and 305.Fn fetchStat 306are similar to 307.Fn fetchXGetURL , 308.Fn fetchGetURL , 309.Fn fetchPutURL , 310and 311.Fn fetchStatURL , 312except that they expect a pre-parsed URL in the form of a pointer to 313a 314.Vt struct url 315rather than a string. 316.Pp 317All of the 318.Fn fetchXGetXXX , 319.Fn fetchGetXXX , 320and 321.Fn fetchPutXXX 322functions return a pointer to a stream which can be used to read or 323write data from or to the requested document, respectively. 324Note that 325although the implementation details of the individual access methods 326vary, it can generally be assumed that a stream returned by one of the 327.Fn fetchXGetXXX 328or 329.Fn fetchGetXXX 330functions is read-only, and that a stream returned by one of the 331.Fn fetchPutXXX 332functions is write-only. 333.Sh PROTOCOL INDEPENDENT FLAGS 334If the 335.Ql i 336(if-modified-since) flag is specified, the library will try to fetch 337the content only if it is newer than 338.Va last_modified . 339For HTTP an 340.Li If-Modified-Since 341HTTP header is sent. 342For FTP a 343.Li MTDM 344command is sent first and compared locally. 345For FILE the source file is compared. 346.Sh FILE SCHEME 347.Fn fetchXGetFile , 348.Fn fetchGetFile , 349and 350.Fn fetchPutFile 351provide access to documents which are files in a locally mounted file 352system. 353Only the 354.Aq document 355component of the URL is used. 356.Pp 357.Fn fetchXGetFile 358and 359.Fn fetchGetFile 360do not accept any flags. 361.Pp 362.Fn fetchPutFile 363accepts the 364.Ql a 365(append to file) flag. 366If that flag is specified, the data written to 367the stream returned by 368.Fn fetchPutFile 369will be appended to the previous contents of the file, instead of 370replacing them. 371.Sh FTP SCHEME 372.Fn fetchXGetFTP , 373.Fn fetchGetFTP , 374and 375.Fn fetchPutFTP 376implement the FTP protocol as described in RFC 959. 377.Pp 378By default 379.Nm libfetch 380will attempt to use passive mode first and only fallback to active mode 381if the server reports a syntax error. 382If the 383.Ql a 384(active) flag is specified, a passive connection is not tried and active mode 385is used directly. 386.Pp 387If the 388.Ql l 389(low) flag is specified, data sockets will be allocated in the low (or 390default) port range instead of the high port range (see 391.Xr ip 4 ) . 392.Pp 393If the 394.Ql d 395(direct) flag is specified, 396.Fn fetchXGetFTP , 397.Fn fetchGetFTP , 398and 399.Fn fetchPutFTP 400will use a direct connection even if a proxy server is defined. 401.Pp 402If no user name or password is given, the 403.Nm fetch 404library will attempt an anonymous login, with user name "anonymous" 405and password "anonymous@\*[Lt]hostname\*[Gt]". 406.Sh HTTP SCHEME 407The 408.Fn fetchXGetHTTP , 409.Fn fetchGetHTTP , 410and 411.Fn fetchPutHTTP 412functions implement the HTTP/1.1 protocol. 413With a little luck, there is 414even a chance that they comply with RFC 2616 and RFC 2617. 415.Pp 416If the 417.Ql d 418(direct) flag is specified, 419.Fn fetchXGetHTTP , 420.Fn fetchGetHTTP , 421and 422.Fn fetchPutHTTP 423will use a direct connection even if a proxy server is defined. 424.Pp 425Since there seems to be no good way of implementing the HTTP PUT 426method in a manner consistent with the rest of the 427.Nm fetch 428library, 429.Fn fetchPutHTTP 430is currently unimplemented. 431.Sh AUTHENTICATION 432Apart from setting the appropriate environment variables and 433specifying the user name and password in the URL or the 434.Vt struct url , 435the calling program has the option of defining an authentication 436function with the following prototype: 437.Pp 438.Ft int 439.Fn myAuthMethod "struct url *u" 440.Pp 441The callback function should fill in the 442.Fa user 443and 444.Fa pwd 445fields in the provided 446.Vt struct url 447and return 0 on success, or any other value to indicate failure. 448.Pp 449To register the authentication callback, simply set 450.Va fetchAuthMethod 451to point at it. 452The callback will be used whenever a site requires authentication and 453the appropriate environment variables are not set. 454.Pp 455This interface is experimental and may be subject to change. 456.Sh RETURN VALUES 457.Fn fetchParseURL 458returns a pointer to a 459.Vt struct url 460containing the individual components of the URL. 461If it is 462unable to allocate memory, or the URL is syntactically incorrect, 463.Fn fetchParseURL 464returns a 465.Dv NULL 466pointer. 467.Pp 468The 469.Fn fetchStat 470functions return 0 on success and \-1 on failure. 471.Pp 472All other functions return a stream pointer which may be used to 473access the requested document, or 474.Dv NULL 475if an error occurred. 476.Pp 477The following error codes are defined in 478.In fetch.h : 479.Bl -tag -width 18n 480.It Bq Er FETCH_ABORT 481Operation aborted 482.It Bq Er FETCH_AUTH 483Authentication failed 484.It Bq Er FETCH_DOWN 485Service unavailable 486.It Bq Er FETCH_EXISTS 487File exists 488.It Bq Er FETCH_FULL 489File system full 490.It Bq Er FETCH_INFO 491Informational response 492.It Bq Er FETCH_MEMORY 493Insufficient memory 494.It Bq Er FETCH_MOVED 495File has moved 496.It Bq Er FETCH_NETWORK 497Network error 498.It Bq Er FETCH_OK 499No error 500.It Bq Er FETCH_PROTO 501Protocol error 502.It Bq Er FETCH_RESOLV 503Resolver error 504.It Bq Er FETCH_SERVER 505Server error 506.It Bq Er FETCH_TEMP 507Temporary error 508.It Bq Er FETCH_TIMEOUT 509Operation timed out 510.It Bq Er FETCH_UNAVAIL 511File is not available 512.It Bq Er FETCH_UNKNOWN 513Unknown error 514.It Bq Er FETCH_URL 515Invalid URL 516.El 517.Pp 518The accompanying error message includes a protocol-specific error code 519and message, e.g.\& "File is not available (404 Not Found)" 520.Sh ENVIRONMENT 521.Bl -tag -width ".Ev FETCH_BIND_ADDRESS" 522.It Ev FETCH_BIND_ADDRESS 523Specifies a host name or IP address to which sockets used for outgoing 524connections will be bound. 525.It Ev FTP_LOGIN 526Default FTP login if none was provided in the URL. 527.It Ev FTP_PASSIVE_MODE 528If set to anything but 529.Ql no , 530forces the FTP code to use passive mode. 531.It Ev FTP_PASSWORD 532Default FTP password if the remote server requests one and none was 533provided in the URL. 534.It Ev FTP_PROXY 535URL of the proxy to use for FTP requests. 536The document part is ignored. 537FTP and HTTP proxies are supported; if no scheme is specified, FTP is 538assumed. 539If the proxy is an FTP proxy, 540.Nm libfetch 541will send 542.Ql user@host 543as user name to the proxy, where 544.Ql user 545is the real user name, and 546.Ql host 547is the name of the FTP server. 548.Pp 549If this variable is set to an empty string, no proxy will be used for 550FTP requests, even if the 551.Ev HTTP_PROXY 552variable is set. 553.It Ev ftp_proxy 554Same as 555.Ev FTP_PROXY , 556for compatibility. 557.It Ev HTTP_AUTH 558Specifies HTTP authorization parameters as a colon-separated list of 559items. 560The first and second item are the authorization scheme and realm 561respectively; further items are scheme-dependent. 562Currently, only basic authorization is supported. 563.Pp 564Basic authorization requires two parameters: the user name and 565password, in that order. 566.Pp 567This variable is only used if the server requires authorization and 568no user name or password was specified in the URL. 569.It Ev HTTP_PROXY 570URL of the proxy to use for HTTP requests. 571The document part is ignored. 572Only HTTP proxies are supported for HTTP requests. 573If no port number is specified, the default is 3128. 574.Pp 575Note that this proxy will also be used for FTP documents, unless the 576.Ev FTP_PROXY 577variable is set. 578.It Ev http_proxy 579Same as 580.Ev HTTP_PROXY , 581for compatibility. 582.It Ev HTTP_PROXY_AUTH 583Specifies authorization parameters for the HTTP proxy in the same 584format as the 585.Ev HTTP_AUTH 586variable. 587.Pp 588This variable is used if and only if connected to an HTTP proxy, and 589is ignored if a user and/or a password were specified in the proxy 590URL. 591.It Ev HTTP_REFERER 592Specifies the referrer URL to use for HTTP requests. 593If set to 594.Dq auto , 595the document URL will be used as referrer URL. 596.It Ev HTTP_USER_AGENT 597Specifies the User-Agent string to use for HTTP requests. 598This can be useful when working with HTTP origin or proxy servers that 599differentiate between user agents. 600.It Ev NETRC 601Specifies a file to use instead of 602.Pa ~/.netrc 603to look up login names and passwords for FTP sites. 604See 605.Xr ftp 1 606for a description of the file format. 607This feature is experimental. 608.It Ev NO_PROXY 609Either a single asterisk, which disables the use of proxies 610altogether, or a comma- or whitespace-separated list of hosts for 611which proxies should not be used. 612.It Ev no_proxy 613Same as 614.Ev NO_PROXY , 615for compatibility. 616.El 617.Sh EXAMPLES 618To access a proxy server on 619.Pa proxy.example.com 620port 8080, set the 621.Ev HTTP_PROXY 622environment variable in a manner similar to this: 623.Pp 624.Dl HTTP_PROXY=http://proxy.example.com:8080 625.Pp 626If the proxy server requires authentication, there are 627two options available for passing the authentication data. 628The first method is by using the proxy URL: 629.Pp 630.Dl HTTP_PROXY=http://\*[Lt]user\*[Gt]:\*[Lt]pwd\*[Gt]@proxy.example.com:8080 631.Pp 632The second method is by using the 633.Ev HTTP_PROXY_AUTH 634environment variable: 635.Bd -literal -offset indent 636HTTP_PROXY=http://proxy.example.com:8080 637HTTP_PROXY_AUTH=basic:*:\*[Lt]user\*[Gt]:\*[Lt]pwd\*[Gt] 638.Ed 639.Pp 640To disable the use of a proxy for an HTTP server running on the local 641host, define 642.Ev NO_PROXY 643as follows: 644.Bd -literal -offset indent 645NO_PROXY=localhost,127.0.0.1 646.Ed 647.Sh SEE ALSO 648.\" .Xr fetch 1 , 649.\" .Xr ftpio 3 , 650.Xr ftp 1 , 651.Xr ip 4 652.Rs 653.%A J. Postel 654.%A J. K. Reynolds 655.%D October 1985 656.%B File Transfer Protocol 657.%O RFC 959 658.Re 659.Rs 660.%A P. Deutsch 661.%A A. Emtage 662.%A A. Marine 663.%D May 1994 664.%T How to Use Anonymous FTP 665.%O RFC 1635 666.Re 667.Rs 668.%A T. Berners-Lee 669.%A L. Masinter 670.%A M. McCahill 671.%D December 1994 672.%T Uniform Resource Locators (URL) 673.%O RFC 1738 674.Re 675.Rs 676.%A R. Fielding 677.%A J. Gettys 678.%A J. Mogul 679.%A H. Frystyk 680.%A L. Masinter 681.%A P. Leach 682.%A T. Berners-Lee 683.%D January 1999 684.%B Hypertext Transfer Protocol -- HTTP/1.1 685.%O RFC 2616 686.Re 687.Rs 688.%A J. Franks 689.%A P. Hallam-Baker 690.%A J. Hostetler 691.%A S. Lawrence 692.%A P. Leach 693.%A A. Luotonen 694.%A L. Stewart 695.%D June 1999 696.%B HTTP Authentication: Basic and Digest Access Authentication 697.%O RFC 2617 698.Re 699.Sh HISTORY 700The 701.Nm fetch 702library first appeared in 703.Fx 3.0 . 704.Sh AUTHORS 705.An -nosplit 706The 707.Nm fetch 708library was mostly written by 709.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org 710with numerous suggestions from 711.An Jordan K. Hubbard Aq jkh@FreeBSD.org , 712.An Eugene Skepner Aq eu@qub.com 713and other 714.Fx 715developers. 716It replaces the older 717.Nm ftpio 718library written by 719.An Poul-Henning Kamp Aq phk@FreeBSD.org 720and 721.An Jordan K. Hubbard Aq jkh@FreeBSD.org . 722.Pp 723This manual page was written by 724.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org . 725.Sh BUGS 726Some parts of the library are not yet implemented. 727The most notable 728examples of this are 729.Fn fetchPutHTTP 730and FTP proxy support. 731.Pp 732There is no way to select a proxy at run-time other than setting the 733.Ev HTTP_PROXY 734or 735.Ev FTP_PROXY 736environment variables as appropriate. 737.Pp 738.Nm libfetch 739does not understand or obey 305 (Use Proxy) replies. 740.Pp 741Error numbers are unique only within a certain context; the error 742codes used for FTP and HTTP overlap, as do those used for resolver and 743system errors. 744For instance, error code 202 means "Command not 745implemented, superfluous at this site" in an FTP context and 746"Accepted" in an HTTP context. 747.Pp 748.Fn fetchStatFTP 749does not check that the result of an MDTM command is a valid date. 750.Pp 751The man page is incomplete, poorly written and produces badly 752formatted text. 753.Pp 754The error reporting mechanism is unsatisfactory. 755.Pp 756Some parts of the code are not fully reentrant. 757