Commit | Line | Data |
---|---|---|
d4ee6ee2 JM |
1 | #pragma GCC diagnostic ignored "-Wunused-but-set-variable" |
2 | ||
3 | #include "sftpd.h" | |
4 | #include "string.h" | |
5 | #include "stdlib.h" | |
6 | ||
7 | extern "C" { | |
8 | #include "uip.h" | |
9 | } | |
10 | ||
11 | #define ISO_nl 0x0a | |
12 | #define ISO_cr 0x0d | |
13 | #define ISO_sp 0x20 | |
14 | ||
15 | #define DEBUG_PRINTF(...) | |
16 | ||
17 | Sftpd::Sftpd() | |
18 | { | |
19 | fd = NULL; | |
20 | state = STATE_NORMAL; | |
21 | outbuf = NULL; | |
22 | filename= NULL; | |
23 | } | |
24 | ||
25 | Sftpd::~Sftpd() | |
26 | { | |
27 | if (fd != NULL) { | |
28 | fclose(fd); | |
29 | } | |
30 | } | |
31 | ||
32 | int Sftpd::senddata() | |
33 | { | |
34 | if (outbuf != NULL) { | |
35 | DEBUG_PRINTF("sftp: senddata %s\n", outbuf); | |
36 | strcpy((char *)uip_appdata, outbuf); | |
37 | uip_send(uip_appdata, strlen(outbuf)); | |
38 | } | |
39 | return 0; | |
40 | } | |
41 | ||
42 | int Sftpd::handle_command() | |
43 | { | |
44 | PSOCK_BEGIN(&sin); | |
45 | ||
46 | do { | |
47 | PSOCK_READTO(&sin, ISO_nl); | |
48 | buf[PSOCK_DATALEN(&sin) - 1] = 0; | |
49 | int len = PSOCK_DATALEN(&sin) - 1; | |
50 | DEBUG_PRINTF("sftp: got command: %s, %d\n", buf, len); | |
51 | ||
52 | if (state == STATE_CONNECTED) { | |
53 | if (strncmp(buf, "USER", 4) == 0) { | |
54 | outbuf = "!user logged in\n"; | |
55 | ||
56 | } else if (strncmp(buf, "KILL", 4) == 0) { | |
57 | if (len < 6) { | |
58 | outbuf = "- incomplete KILL command\n"; | |
59 | } else { | |
60 | char *fn = &buf[5]; | |
61 | int s = remove(fn); | |
62 | if (s == 0) outbuf = "+ deleted\n"; | |
63 | else outbuf = "- delete failed\n"; | |
64 | } | |
65 | ||
66 | } else if (strncmp(buf, "DONE", 4) == 0) { | |
67 | outbuf = "+ exit\n"; | |
68 | state = STATE_CLOSE; | |
69 | ||
70 | } else if (strncmp(buf, "STOR", 4) == 0) { | |
71 | if (len < 11) { | |
72 | outbuf = "- incomplete STOR command\n"; | |
73 | } else { | |
74 | char *fn = &buf[9]; | |
75 | if(this->filename != NULL) free(this->filename); | |
76 | this->filename= strdup(fn); // REMOVE when bug fixed | |
77 | // get { NEW|OLD|APP } | |
78 | if (strncmp(&buf[5], "OLD", 3) == 0) { | |
79 | DEBUG_PRINTF("sftp: Opening file: %s\n", fn); | |
80 | fd = fopen(fn, "w"); | |
81 | if (fd != NULL) { | |
82 | outbuf = "+ new file\n"; | |
83 | state = STATE_GET_LENGTH; | |
84 | } else { | |
85 | outbuf = "- failed\n"; | |
86 | } | |
87 | } else if (strncmp(&buf[5], "APP", 3) == 0) { | |
88 | fd = fopen(fn, "a"); | |
89 | if (fd != NULL) { | |
90 | outbuf = "+ append file\n"; | |
91 | state = STATE_GET_LENGTH; | |
92 | } else { | |
93 | outbuf = "- failed\n"; | |
94 | } | |
95 | } else { | |
96 | outbuf = "- Only OLD|APP supported\n"; | |
97 | } | |
98 | } | |
99 | ||
100 | } else { | |
101 | outbuf = "- Unknown command\n"; | |
102 | } | |
103 | ||
104 | } else if (state == STATE_GET_LENGTH) { | |
105 | if (len < 6 || strncmp(buf, "SIZE", 4) != 0) { | |
106 | fclose(fd); | |
107 | fd = NULL; | |
108 | outbuf = "- Expected size\n"; | |
109 | state = STATE_CONNECTED; | |
110 | ||
111 | } else { | |
112 | filesize = atoi(&buf[5]); | |
113 | if (filesize > 0) { | |
114 | outbuf = "+ ok, waiting for file\n"; | |
115 | state = STATE_DOWNLOAD; | |
116 | } else { | |
117 | fclose(fd); | |
118 | fd = NULL; | |
119 | outbuf = "- bad filesize\n"; | |
120 | state = STATE_CONNECTED; | |
121 | } | |
122 | } | |
123 | ||
124 | } else { | |
125 | DEBUG_PRINTF("WTF state: %d\n", state); | |
126 | } | |
127 | ||
128 | } while(state == STATE_CONNECTED || state == STATE_GET_LENGTH); | |
129 | ||
130 | PSOCK_END(&sin); | |
131 | } | |
132 | ||
133 | int Sftpd::handle_download() | |
134 | { | |
135 | // Note this is not using PSOCK and it consumes all read data | |
136 | char *readptr = (char *)uip_appdata; | |
137 | unsigned int readlen = uip_datalen(); | |
138 | DEBUG_PRINTF("sftp: starting download, expecting %d bytes, read %d\n", filesize, readlen); | |
139 | ||
140 | if (filesize > 0 && readlen > 0) { | |
141 | if (readlen > filesize) readlen = filesize; | |
142 | if (fwrite(readptr, 1, readlen, fd) != readlen) { | |
143 | DEBUG_PRINTF("sftp: Error writing file\n"); | |
144 | fclose(fd); | |
145 | fd = NULL; | |
146 | outbuf = "- Error saving file\n"; | |
147 | state = STATE_CONNECTED; | |
148 | return 0; | |
149 | } | |
150 | filesize -= readlen; | |
151 | DEBUG_PRINTF("sftp: saved %d bytes %d left\n", readlen, filesize); | |
d4ee6ee2 JM |
152 | } |
153 | if (filesize == 0) { | |
154 | DEBUG_PRINTF("sftp: download complete\n"); | |
155 | fclose(fd); | |
156 | fd = NULL; | |
157 | outbuf = "+ Saved file\n"; | |
158 | state = STATE_CONNECTED; | |
159 | return 0; | |
160 | } | |
161 | return 1; | |
162 | } | |
163 | ||
164 | int Sftpd::acked() | |
165 | { | |
166 | outbuf= NULL; | |
167 | return 0; | |
168 | } | |
169 | ||
170 | ||
171 | void Sftpd::appcall(void) | |
172 | { | |
173 | if (uip_connected()) { | |
174 | // TODO check for other connections | |
175 | PSOCK_INIT(&sin, buf, sizeof(buf)); | |
176 | state = STATE_CONNECTED; | |
177 | outbuf = "+Smoothie SFTP Service\n"; | |
178 | } | |
179 | ||
180 | if (state == STATE_CLOSE) { | |
181 | DEBUG_PRINTF("sftp: state close\n"); | |
182 | state = STATE_NORMAL; | |
183 | uip_close(); | |
184 | return; | |
185 | } | |
186 | ||
187 | if (uip_closed() || uip_aborted() || uip_timedout()) { | |
188 | DEBUG_PRINTF("sftp: closed\n"); | |
189 | if (fd != NULL) | |
190 | fclose(fd); | |
191 | fd = NULL; | |
192 | state = STATE_NORMAL; | |
193 | return; | |
194 | } | |
195 | ||
196 | if (uip_acked()) { | |
197 | DEBUG_PRINTF("sftp: acked\n"); | |
198 | this->acked(); | |
199 | } | |
200 | ||
201 | if (uip_newdata()) { | |
202 | DEBUG_PRINTF("sftp: newdata\n"); | |
203 | if (state == STATE_DOWNLOAD) { | |
204 | if(handle_download() == 0) { | |
205 | // we need to reset the input PSOCK again before using it after using the raw input buffer | |
206 | PSOCK_INIT(&sin, buf, sizeof(buf)); | |
207 | } | |
208 | } else { | |
209 | handle_command(); | |
210 | } | |
211 | } | |
212 | ||
213 | if (uip_rexmit() || uip_newdata() || uip_acked() || uip_connected() || uip_poll()) { | |
214 | this->senddata(); | |
215 | } | |
216 | ||
217 | } | |
218 | ||
219 | void Sftpd::init(void) | |
220 | { | |
221 | ||
222 | } | |
223 | ||
224 |