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 };