bro | URI-based multiplexer |
| download: http://git.y1.nz/archives/bro.tar.gz | |
| README | Files | Log | Refs |
main.c
1 #include <stdio.h> /* printf */
2 #include <string.h> /* strlen */
3 #include <unistd.h> /* execlp, access */
4 #include <sys/wait.h> /* waitpid */
5 #include <stdlib.h> /* exit */
6 #include <errno.h> /* errno */
7 #include <fcntl.h> /* creat */
8
9 #include "okra.h"
10 #include "config.h"
11
12 #define FATAL(message) { \
13 printf("\033[1;31m" "Fatal: " message "\033[0m" "\n"); \
14 exit(1); \
15 }
16 #define FORKEXEC(arg1, ...) { \
17 pid = fork(); \
18 if (!pid) { \
19 int result; \
20 result = execlp(arg1, arg1, __VA_ARGS__, NULL); \
21 exit(0); \
22 } \
23 waitpid(pid, &child_status, 0); \
24 }
25 #define FFORKEXEC(fname, arg1, ...) { \
26 pid = fork(); \
27 if (!pid) { \
28 int result; \
29 int fd = creat( \
30 fname, \
31 O_CREAT | O_TRUNC | O_WRONLY | \
32 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH \
33 ); \
34 if (fd == -1) { \
35 printf("Failed to create [%s]" "\n", fname); \
36 FATAL("couldnt open/create file :("); \
37 } \
38 dup2(fd, STDOUT_FILENO); \
39 result = execlp(arg1, arg1, __VA_ARGS__, NULL); \
40 if (result == -1) { \
41 int err = errno; \
42 FATAL("Uh oh exec dint work :(("); \
43 } \
44 exit(0); \
45 } \
46 waitpid(pid, &child_status, 0); \
47 }
48
49 pid_t pid;
50 int child_status;
51
52 void
53 ask_to_continue()
54 {
55 char ch;
56
57 // TODO set termios so it's "press y to %s, n or q to quit"
58 printf("Try again?"); fflush(stdout);
59 for (;;) {
60 switch (getchar()) {
61 case 'y': return;
62 case 'n':
63 case 'q': FATAL("Cancelled.");
64 }
65 }
66 }
67
68 void
69 ensure_file_exists(const char *path)
70 {
71 if (!access(path, O_RDONLY)) return;
72 printf("Couldn't access local file [%s]" "\n", path);
73 FATAL("File is inaccessible");
74 }
75
76 int
77 streq(const char *a, const char *b)
78 {
79 if (a == NULL && b == NULL) return 1;
80 if (a == NULL || b == NULL) return 0;
81 int i = 0;
82 for (;;) {
83 if (a[i] != b[i]) return 0;
84 if (a[i] == '\0') return 1;
85 i++;
86 }
87 }
88
89 const char *
90 get_extension(const char *filename)
91 {
92 int length = strlen(filename);
93 int i = length-1;
94 for (;;) {
95 i--;
96 if (i < 0) return NULL;
97 if (filename[i] == '.')
98 return filename + (i+1);
99 }
100 }
101
102 const char *
103 get_raw_file(OkraUri *uri)
104 {
105 const char *ret = NULL;
106
107 /* default to "file" scheme */
108 if (uri->scheme == NULL || streq(uri->scheme, "file"))
109 return uri->path;
110
111 if (streq(uri->scheme, "mailto"))
112 FATAL("TODO open a mail client then exit?");
113
114 if (streq(uri->scheme, "http") || streq(uri->scheme, "https")) {
115 child_status = 1;
116 ret = DEFAULT_SESSION_DIR "/current.html";
117 for (;;) {
118 if (child_status == 0) break;
119 FFORKEXEC(ret, "wget", "-O", "-", uri->uri);
120 if (child_status != 0) {
121 printf("Exit status was %d" "\n", child_status);
122 ask_to_continue();
123 }
124 }
125 return ret;
126 }
127
128 if (streq(uri->scheme, "gopher")) {
129 ret = DEFAULT_SESSION_DIR "/current.gph";
130 FFORKEXEC(ret, "hurl", uri->uri);
131 return ret;
132 }
133
134 if (streq(uri->scheme, "ftp"))
135 FATAL("TODO retrieve ftp page.");
136
137 printf("Scheme: [%s]" "\n", uri->scheme);
138 FATAL("Unhandled scheme.");
139 exit(1);
140 }
141
142 const char *
143 get_digested_file(OkraUri *uri, const char *raw_file)
144 {
145 const char *ret = NULL;
146 const char *ext = get_extension(uri->uri);
147
148 if (streq(ext, "txt")) return raw_file;
149
150 if (streq(ext, "html")) {
151 ret = DEFAULT_SESSION_DIR "/current.md";
152 FORKEXEC(
153 "digest-html",
154 "-b", uri->uri,
155 "-o", ret,
156 raw_file
157 );
158 if (child_status != 0) FATAL("Failed to digest HTML.");
159 return ret;
160 }
161
162 if (streq(ext, "gph")) {
163 ret = DEFAULT_SESSION_DIR "/current.md";
164 FORKEXEC("digest-gopher", "-o", ret, raw_file);
165 if (child_status != 0) FATAL("Failed to digest gohper.");
166 return ret;
167 }
168
169 /* default based on scheme */
170 // TODO is there a better way?
171 if (streq(uri->scheme, "http") || streq(uri->scheme, "https")) {
172 ret = DEFAULT_SESSION_DIR "/current.md";
173 FORKEXEC(
174 "digest-html",
175 "-b", uri->uri,
176 "-o", ret,
177 raw_file
178 );
179 if (child_status != 0) FATAL("Failed to digest HTML.");
180 return ret;
181 }
182 if (streq(uri->scheme, "gopher")) {
183 ret = DEFAULT_SESSION_DIR "/current.md";
184 FORKEXEC("digest-gopher", "-o", ret, raw_file);
185 if (child_status != 0) FATAL("Failed to digest gopher.");
186 return ret;
187 }
188
189 printf("No digester, defaulting to raw" "\n");
190 return raw_file;
191 }
192
193 int
194 main(int argc, const char *argv[])
195 {
196 if (argc != 2) {
197 printf("Usage: %s URI" "\n", argv[0]);
198 return 1;
199 }
200
201 OkraUri *uri = okra_parse(argv[1]);
202 if (uri == NULL) FATAL("Invalid URI.");
203
204 FORKEXEC("rm", "-f", "current.md", "current.gph", "current.html");
205
206 const char *raw_file = get_raw_file(uri);
207 if (raw_file == NULL) FATAL("No file to view.");
208 ensure_file_exists(raw_file);
209
210 const char *lwl_file = get_digested_file(uri, raw_file);
211 ensure_file_exists(lwl_file);
212 FORKEXEC("lwl", lwl_file);
213
214 okra_free(uri);
215 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.