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(NULL, 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 av_freep(&h->priv_data);
00076 return 0;
00077 }
00078
00079 static int gopher_open(URLContext *h, const char *uri, int flags)
00080 {
00081 GopherContext *s;
00082 char hostname[1024], auth[1024], path[1024], buf[1024];
00083 int port, err;
00084
00085 h->is_streamed = 1;
00086
00087 s = av_malloc(sizeof(GopherContext));
00088 if (!s) {
00089 return AVERROR(ENOMEM);
00090 }
00091 h->priv_data = s;
00092
00093
00094 av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
00095 path, sizeof(path), uri);
00096
00097 if (port < 0)
00098 port = 70;
00099
00100 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
00101
00102 s->hd = NULL;
00103 err = ffurl_open(&s->hd, buf, AVIO_RDWR);
00104 if (err < 0)
00105 goto fail;
00106
00107 if ((err = gopher_connect(h, path)) < 0)
00108 goto fail;
00109 return 0;
00110 fail:
00111 gopher_close(h);
00112 return err;
00113 }
00114
00115 static int gopher_read(URLContext *h, uint8_t *buf, int size)
00116 {
00117 GopherContext *s = h->priv_data;
00118 int len = ffurl_read(s->hd, buf, size);
00119 return len;
00120 }
00121
00122
00123 URLProtocol ff_gopher_protocol = {
00124 .name = "gopher",
00125 .url_open = gopher_open,
00126 .url_read = gopher_read,
00127 .url_write = gopher_write,
00128 .url_close = gopher_close,
00129 };