00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "libavutil/avstring.h"
00026 #include "avformat.h"
00027 #include "internal.h"
00028 #include "network.h"
00029 #include "url.h"
00030
00031 typedef struct {
00032 URLContext *hd;
00033 } GopherContext;
00034
00035 static int gopher_write(URLContext *h, const uint8_t *buf, int size)
00036 {
00037 GopherContext *s = h->priv_data;
00038 return ffurl_write(s->hd, buf, size);
00039 }
00040
00041 static int gopher_connect(URLContext *h, const char *path)
00042 {
00043 char buffer[1024];
00044
00045 if (!*path) return AVERROR(EINVAL);
00046 switch (*++path) {
00047 case '5':
00048 case '9':
00049 path = strchr(path, '/');
00050 if (!path) return AVERROR(EINVAL);
00051 break;
00052 default:
00053 av_log(h, AV_LOG_WARNING,
00054 "Gopher protocol type '%c' not supported yet!\n",
00055 *path);
00056 return AVERROR(EINVAL);
00057 }
00058
00059
00060 snprintf(buffer, sizeof(buffer), "%s\r\n", path);
00061
00062 if (gopher_write(h, buffer, strlen(buffer)) < 0)
00063 return AVERROR(EIO);
00064
00065 return 0;
00066 }
00067
00068 static int gopher_close(URLContext *h)
00069 {
00070 GopherContext *s = h->priv_data;
00071 if (s->hd) {
00072 ffurl_close(s->hd);
00073 s->hd = NULL;
00074 }
00075 return 0;
00076 }
00077
00078 static int gopher_open(URLContext *h, const char *uri, int flags)
00079 {
00080 GopherContext *s = h->priv_data;
00081 char hostname[1024], auth[1024], path[1024], buf[1024];
00082 int port, err;
00083
00084 h->is_streamed = 1;
00085
00086
00087 av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
00088 path, sizeof(path), uri);
00089
00090 if (port < 0)
00091 port = 70;
00092
00093 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
00094
00095 s->hd = NULL;
00096 err = ffurl_open(&s->hd, buf, AVIO_FLAG_READ_WRITE,
00097 &h->interrupt_callback, NULL);
00098 if (err < 0)
00099 goto fail;
00100
00101 if ((err = gopher_connect(h, path)) < 0)
00102 goto fail;
00103 return 0;
00104 fail:
00105 gopher_close(h);
00106 return err;
00107 }
00108
00109 static int gopher_read(URLContext *h, uint8_t *buf, int size)
00110 {
00111 GopherContext *s = h->priv_data;
00112 int len = ffurl_read(s->hd, buf, size);
00113 return len;
00114 }
00115
00116
00117 URLProtocol ff_gopher_protocol = {
00118 .name = "gopher",
00119 .url_open = gopher_open,
00120 .url_read = gopher_read,
00121 .url_write = gopher_write,
00122 .url_close = gopher_close,
00123 .priv_data_size = sizeof(GopherContext),
00124 .flags = URL_PROTOCOL_FLAG_NETWORK,
00125 };