fixed typo enable_sqllite -> enable_sqlite
[platform/upstream/libsoup.git] / libsoup / soup-directory-input-stream.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2008, 2010 Red Hat, Inc.
4  * Copyright (C) 2010 Igalia, S.L.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27
28 #include "soup-directory-input-stream.h"
29 #include "soup.h"
30
31 #define INIT_STRING "<html>\n<body>\n<table><th align=\"left\">Name</th><th>Size</th><th>Date Modified</th>\n"
32 #define ROW_FORMAT  "<td><a href=\"%s\">%s</a></td><td align=\"right\">%s</td><td align=\"right\" margin=8>%s</td>\n"
33 #define EXIT_STRING "</table>\n</html>\n"
34
35 G_DEFINE_TYPE (SoupDirectoryInputStream, soup_directory_input_stream, G_TYPE_INPUT_STREAM)
36
37 static SoupBuffer *
38 soup_directory_input_stream_parse_info (SoupDirectoryInputStream *stream,
39                                         GFileInfo *info)
40 {
41         SoupBuffer *buffer;
42         GString *string;
43         const char *file_name;
44         char *escaped, *path, *xml_string, *size, *time;
45         GTimeVal modified;
46         GDateTime *modification_time;
47
48         if (!g_file_info_get_name (info))
49                 return NULL;
50
51         file_name = g_file_info_get_display_name (info);
52         if (!file_name) {
53                 file_name = g_file_info_get_name (info);
54                 /* FIXME: convert somehow? */
55                 if (!g_utf8_validate (file_name, -1, NULL))
56                         return NULL;
57         }
58         string = g_string_new ("<tr>");
59
60         xml_string = g_markup_escape_text (file_name, -1);
61         escaped = g_uri_escape_string (file_name, NULL, FALSE);
62         path = g_strconcat (stream->uri, G_DIR_SEPARATOR_S, escaped, NULL);
63         size = g_format_size (g_file_info_get_size (info));
64         g_file_info_get_modification_time (info, &modified);
65         modification_time = g_date_time_new_from_timeval_local (&modified);
66         time = g_date_time_format (modification_time, "%X %x");
67         g_date_time_unref (modification_time);
68
69         g_string_append_printf (string, ROW_FORMAT, path, xml_string, size, time);
70         g_string_append (string, "</tr>\n");
71         buffer = soup_buffer_new (SOUP_MEMORY_TAKE, string->str, string->len);
72
73         g_free (time);
74         g_free (escaped);
75         g_free (size);
76         g_free (path);
77         g_free (xml_string);
78         g_string_free (string, FALSE);
79
80         return buffer;
81 }
82
83 static SoupBuffer *
84 soup_directory_input_stream_read_next_file (SoupDirectoryInputStream  *stream,
85                                             GCancellable              *cancellable,
86                                             GError                   **error)
87 {
88         GFileInfo *info;
89         SoupBuffer *buffer;
90         GError *err = NULL;
91
92         do {
93                 info = g_file_enumerator_next_file (stream->enumerator, cancellable, &err);
94                 if (info == NULL) {
95                         if (err) {
96                                 g_propagate_error (error, err);
97                                 return NULL;
98                         } else if (!stream->done) {
99                                 stream->done = TRUE;
100                                 return soup_buffer_new (SOUP_MEMORY_STATIC,
101                                                         EXIT_STRING,
102                                                         sizeof (EXIT_STRING));
103                         } else {
104                                 return NULL;
105                         }
106                 }
107
108                 buffer = soup_directory_input_stream_parse_info (stream, info);
109                 g_object_unref (info);
110         } while (buffer == NULL);
111
112         return buffer;
113 }
114
115 static gssize
116 soup_directory_input_stream_read (GInputStream  *input,
117                                   void          *buffer,
118                                   gsize          count,
119                                   GCancellable  *cancellable,
120                                   GError       **error)
121 {
122         SoupDirectoryInputStream *stream = SOUP_DIRECTORY_INPUT_STREAM (input);
123         gsize total, size;
124
125         for (total = 0; total < count; total += size) {
126                 if (stream->buffer == NULL) {
127                         stream->buffer = soup_directory_input_stream_read_next_file (stream, cancellable, error);
128                         if (stream->buffer == NULL) {
129                                 /* FIXME: Is this correct or should we forward the error? */
130                                 if (total)
131                                         g_clear_error (error);
132                                 return total;
133                         }
134                 }
135
136                 size = MIN (stream->buffer->length, count - total);
137                 memcpy ((char *)buffer + total, stream->buffer->data, size);
138                 if (size == stream->buffer->length) {
139                         soup_buffer_free (stream->buffer);
140                         stream->buffer = NULL;
141                 } else {
142                         SoupBuffer *sub = soup_buffer_new_subbuffer (stream->buffer,
143                                                                      size,
144                                                                      stream->buffer->length - size);
145                         soup_buffer_free (stream->buffer);
146                         stream->buffer = sub;
147                 }
148         }
149
150         return total;
151 }
152
153 static gboolean
154 soup_directory_input_stream_close (GInputStream  *input,
155                                    GCancellable  *cancellable,
156                                    GError       **error)
157 {
158         SoupDirectoryInputStream *stream = SOUP_DIRECTORY_INPUT_STREAM (input);
159         gboolean result;
160
161         if (stream->buffer) {
162                 soup_buffer_free (stream->buffer);
163                 stream->buffer = NULL;
164         }
165
166         result = g_file_enumerator_close (stream->enumerator,
167                                           cancellable,
168                                           error);
169         g_object_unref (stream->enumerator);
170         stream->enumerator = NULL;
171
172         g_free (stream->uri);
173         stream->uri = NULL;
174
175         return result;
176 }
177
178 static void
179 soup_directory_input_stream_class_init (SoupDirectoryInputStreamClass *stream_class)
180 {
181         GInputStreamClass *inputstream_class = G_INPUT_STREAM_CLASS (stream_class);
182
183         inputstream_class->read_fn = soup_directory_input_stream_read;
184         inputstream_class->close_fn = soup_directory_input_stream_close;
185 }
186
187 static void
188 soup_directory_input_stream_init (SoupDirectoryInputStream *stream)
189 {
190         stream->buffer = soup_buffer_new (SOUP_MEMORY_STATIC,
191                                           INIT_STRING,
192                                           sizeof (INIT_STRING));
193 }
194
195 GInputStream *
196 soup_directory_input_stream_new (GFileEnumerator *enumerator,
197                                  SoupURI         *uri)
198 {
199         GInputStream *stream;
200
201         g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
202         g_return_val_if_fail (uri != NULL, NULL);
203
204         stream = g_object_new (SOUP_TYPE_DIRECTORY_INPUT_STREAM, NULL);
205
206         SOUP_DIRECTORY_INPUT_STREAM (stream)->enumerator = g_object_ref (enumerator);
207         SOUP_DIRECTORY_INPUT_STREAM (stream)->uri = soup_uri_to_string (uri, FALSE);
208
209         return stream;
210 }
211