We can now issue SSH commands to the server
[printdrop.git] / Source / AppController.m
1 /*
2 * PrintDrop
3 * Copyright (c) 2008, Blue Static <http://www.bluestatic.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
10 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17 #import "AppController.h"
18 #import <libssh2.h>
19 #import <sys/socket.h>
20 #import <arpa/inet.h>
21 #include <netdb.h>
22
23 @interface AppController (Private)
24
25 //- (BOOL)uploadFile;
26 - (void)setStatus:(NSString *)msg isError:(BOOL)error;
27
28 @end
29
30
31 @implementation AppController
32
33 /**
34 * Set up the printer list
35 */
36 - (id)init
37 {
38 if (self = [super init])
39 {
40 printers = [NSMutableArray array];
41
42 NSArray *values = [NSArray arrayWithObjects:@"Double-Sided, Stapled $0.05", @"publp", nil];
43 NSArray *keys = [NSArray arrayWithObjects:@"displayName", @"unixName", nil];
44 [printers addObject:[NSDictionary dictionaryWithObjects:values forKeys:keys]];
45
46 values = [NSArray arrayWithObjects:@"Single-Sided, Stapled $0.10", @"pubps", nil];
47 [printers addObject:[NSDictionary dictionaryWithObjects:values forKeys:keys]];
48
49 values = [NSArray arrayWithObjects:@"Double-Sided, Not Stapled $0.05", @"publpns", nil];
50 [printers addObject:[NSDictionary dictionaryWithObjects:values forKeys:keys]];
51
52 values = [NSArray arrayWithObjects:@"Single-Sided, Not Stapled $0.10", @"pubpsns", nil];
53 [printers addObject:[NSDictionary dictionaryWithObjects:values forKeys:keys]];
54 }
55 return self;
56 }
57
58 /**
59 * Sets the status text
60 */
61 - (void)setStatus:(NSString *)msg isError:(BOOL)error
62 {
63 [status setStringValue:msg];
64 if (error)
65 {
66 [status setTextColor:[NSColor redColor]];
67 [progress stopAnimation:self];
68 }
69 else
70 {
71 [status setTextColor:[NSColor blackColor]];
72 }
73 }
74
75 /**
76 * Sends an item to the printer
77 */
78 - (IBAction)print:(id)sender
79 {
80 [progress startAnimation:self];
81 [progress setHidden:NO];
82 [status setHidden:NO];
83
84 NSString *printer = [[printersController selection] valueForKey:@"unixName"];
85 FILE *localFile;
86 struct stat fileInfo;
87
88 [self setStatus:@"Connecting to acs.bu.edu" isError:NO];
89 struct sockaddr_in sin;
90 int sock = socket(AF_INET, SOCK_STREAM, 0);
91 sin.sin_port = htons(22);
92 sin.sin_family = AF_INET;
93
94 struct hostent *host = gethostbyname("acs.bu.edu");
95 memcpy(&sin.sin_addr, host->h_addr_list[0], host->h_length);
96
97 if (connect(sock, (struct sockaddr *)(&sin), sizeof(struct sockaddr_in)) != 0)
98 {
99 return [self setStatus:@"Could not connect to acs.bu.edu" isError:YES];
100 }
101
102 LIBSSH2_SESSION *ssh = libssh2_session_init();
103 if (ssh == NULL)
104 {
105 return [self setStatus:@"Failed to initialize SSH context" isError:YES];
106 }
107
108 if (libssh2_session_startup(ssh, sock))
109 {
110 return [self setStatus:@"Could not tunnel over SSH" isError:YES];
111 }
112
113 if (libssh2_userauth_password(ssh, [[username stringValue] UTF8String], [[password stringValue] UTF8String]))
114 {
115 [self setStatus:@"Bad username/password" isError:YES];
116 goto shutdown;
117 }
118 /*
119 stat([[dragRegion filePath] UTF8String], &fileInfo);
120
121 LIBSSH2_CHANNEL *channel = libssh2_scp_send(ssh, "~/tempupload.pdf", 0755, (unsigned long)fileInfo.st_size);
122 if (!channel)
123 {
124 [self setStatus:@"Unable to open upload SCP session" isError:YES];
125 goto shutdown;
126 }
127
128 [self setStatus:@"Uploading file..." isError:NO];
129
130 localFile = fopen([[dragRegion filePath] UTF8String], "r");
131 char buf[1024];
132 char *pbuf;
133 int numread, numwrote;
134 do
135 {
136 numread = fread(buf, 1, sizeof(buf), localFile);
137 if (numread <= 0)
138 {
139 break;
140 }
141
142 pbuf = buf;
143 do
144 {
145 numwrote = libssh2_channel_write(channel, pbuf, numread);
146 pbuf += numwrote;
147 numread -= numread;
148 } while (numwrote > 0);
149
150 } while(1);
151
152 [self setStatus:@"File uploaded!" isError:NO];
153
154 libssh2_channel_send_eof(channel);
155 libssh2_channel_wait_eof(channel);
156 libssh2_channel_wait_closed(channel);
157 libssh2_channel_free(channel);
158 channel = NULL;
159 */
160
161 LIBSSH2_CHANNEL *channel = libssh2_channel_open_session(ssh);
162 if (!channel)
163 {
164 [self setStatus:@"Could not open SSH channel for printing" isError:YES];
165 goto shutdown;
166 }
167
168 if (libssh2_channel_request_pty(channel, "vanilla"))
169 {
170 [self setStatus:@"Could not open ANSI TTY" isError:YES];
171 goto shutdown;
172 }
173
174 if (libssh2_channel_shell(channel))
175 {
176 [self setStatus:@"Failed to open remote shell" isError:YES];
177 goto shutdown;
178 }
179
180 [self setStatus:@"Opened remote SSH shell" isError:NO];
181
182 libssh2_channel_flush_ex(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL);
183
184 /*
185 char *e = malloc(1024 * sizeof(char));
186 libssh2_session_last_error(ssh, &e, NULL, 0);
187 NSLog(@"e = %s", e);
188 */
189
190 libssh2_channel_set_blocking(channel, 0);
191
192 char b[1024];
193 int r;
194 do
195 {
196 memset(&b, '\0', sizeof(b));
197 sleep(1);
198 r = libssh2_channel_read(channel, b, sizeof(b));
199 NSLog(@"b(%i) = %s", r, b);
200 } while (r > 0);
201
202 char *cmd = "touch /u17/ugrad/rsesek/temp.foo\r\n\0";
203 NSLog(@"numbytes = %i", libssh2_channel_write(channel, cmd, sizeof(char) * strlen(cmd)));
204
205 do
206 {
207 memset(&b, '\0', sizeof(b));
208 sleep(1);
209 r = libssh2_channel_read(channel, b, sizeof(b));
210 NSLog(@"b(%i) = %s", r, b);
211 } while (r > 0);
212
213 [self setStatus:@"Printed!" isError:NO];
214
215 libssh2_channel_send_eof(channel);
216 libssh2_channel_eof(channel);
217 libssh2_channel_close(channel);
218
219 shutdown:
220 if (channel)
221 {
222 libssh2_channel_free(channel);
223 channel = NULL;
224 }
225 libssh2_session_disconnect(ssh, "Normal disconnect.");
226 libssh2_session_free(ssh);
227
228 close(sock);
229
230 [progress stopAnimation:self];
231 }
232
233 @end