3 * Copyright (c) 2008, Blue Static <http://www.bluestatic.org>
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.
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.
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
17 #import "AppController.h"
19 #import <sys/socket.h>
23 @interface AppController (Private
)
26 - (void)setStatus
:(NSString
*)msg isError
:(BOOL)error
;
28 - (void)readChannel
:(LIBSSH2_CHANNEL
*)channel
;
33 @implementation AppController
36 * Set up the printer list
40 if (self = [super init
])
42 printers
= [NSMutableArray array
];
44 NSArray
*values
= [NSArray arrayWithObjects
:@
"Double-Sided, Stapled $0.05", @
"publp", nil];
45 NSArray
*keys
= [NSArray arrayWithObjects
:@
"displayName", @
"unixName", nil];
46 [printers addObject
:[NSDictionary dictionaryWithObjects
:values forKeys
:keys
]];
48 values
= [NSArray arrayWithObjects
:@
"Single-Sided, Stapled $0.10", @
"pubps", nil];
49 [printers addObject
:[NSDictionary dictionaryWithObjects
:values forKeys
:keys
]];
51 values
= [NSArray arrayWithObjects
:@
"Double-Sided, Not Stapled $0.05", @
"publpns", nil];
52 [printers addObject
:[NSDictionary dictionaryWithObjects
:values forKeys
:keys
]];
54 values
= [NSArray arrayWithObjects
:@
"Single-Sided, Not Stapled $0.10", @
"pubpsns", nil];
55 [printers addObject
:[NSDictionary dictionaryWithObjects
:values forKeys
:keys
]];
61 * Sets the status text
63 - (void)setStatus
:(NSString
*)msg isError
:(BOOL)error
65 [status setStringValue
:msg
];
68 [status setTextColor
:[NSColor redColor
]];
69 [progress stopAnimation
:self];
73 [status setTextColor
:[NSColor blackColor
]];
78 * Reads through a channel (in non-blocking) mode until there is no more left to read
79 * and then it returns. This calls sleep(1) so that the channel can have time to process.
80 * Be sure this is threaded otherwis the interface will stall.
82 - (void)readChannel
:(LIBSSH2_CHANNEL
*)channel
84 libssh2_channel_set_blocking(channel
, 0);
90 memset(&buf
, '\0', sizeof(buf
));
92 numbytes
= libssh2_channel_read(channel
, buf
, sizeof(buf
));
93 } while (numbytes
> 0);
97 * Sends an item to the printer
99 - (IBAction
)print
:(id)sender
101 [progress startAnimation
:self];
102 [progress setHidden
:NO
];
103 [status setHidden
:NO
];
105 NSString
*printer
= [[printersController selection
] valueForKey
:@
"unixName"];
107 struct stat fileInfo
;
109 [self setStatus
:@
"Connecting to acs.bu.edu" isError
:NO
];
110 struct sockaddr_in sin
;
111 int sock
= socket(AF_INET
, SOCK_STREAM
, 0);
112 sin.sin_port
= htons(22);
113 sin.sin_family
= AF_INET
;
115 struct hostent
*host
= gethostbyname("acs.bu.edu");
116 memcpy(&sin.sin_addr
, host
->h_addr_list
[0], host
->h_length
);
118 if (connect(sock
, (struct sockaddr
*)(&sin
), sizeof(struct sockaddr_in
)) != 0)
120 return [self setStatus
:@
"Could not connect to acs.bu.edu" isError
:YES
];
123 LIBSSH2_SESSION
*ssh
= libssh2_session_init();
126 return [self setStatus
:@
"Failed to initialize SSH context" isError
:YES
];
129 if (libssh2_session_startup(ssh
, sock
))
131 return [self setStatus
:@
"Could not tunnel over SSH" isError
:YES
];
134 if (libssh2_userauth_password(ssh
, [[username stringValue
] UTF8String
], [[password stringValue
] UTF8String
]))
136 [self setStatus
:@
"Bad username/password" isError
:YES
];
140 stat([[dragRegion filePath
] UTF8String
], &fileInfo
);
142 LIBSSH2_CHANNEL
*channel
= libssh2_scp_send(ssh
, "~/__bu_print_drop__.pdf", 0755, (unsigned long)fileInfo.st_size
);
145 [self setStatus
:@
"Unable to open upload SCP session" isError
:YES
];
149 [self setStatus
:@
"Uploading file..." isError
:NO
];
151 localFile
= fopen([[dragRegion filePath
] UTF8String
], "r");
154 int numread
, numwrote
;
157 numread
= fread(buf
, 1, sizeof(buf
), localFile
);
166 numwrote
= libssh2_channel_write(channel
, pbuf
, numread
);
169 } while (numwrote
> 0);
173 [self setStatus
:@
"File uploaded!" isError
:NO
];
175 libssh2_channel_send_eof(channel
);
176 libssh2_channel_wait_eof(channel
);
177 libssh2_channel_wait_closed(channel
);
178 libssh2_channel_free(channel
);
181 channel
= libssh2_channel_open_session(ssh
);
184 [self setStatus
:@
"Could not open SSH channel for printing" isError
:YES
];
188 if (libssh2_channel_request_pty(channel
, "vanilla"))
190 [self setStatus
:@
"Could not open ANSI TTY" isError
:YES
];
194 if (libssh2_channel_shell(channel
))
196 [self setStatus
:@
"Failed to open remote shell" isError
:YES
];
200 [self setStatus
:@
"Opened remote SSH shell" isError
:NO
];
203 [self readChannel
:channel
];
205 // send the job to lpr
206 char *cmd
= (char *)[[NSString stringWithFormat
:@
"touch ~/print-%@.drop\r\n\0", printer
] UTF8String
];
207 libssh2_channel_write(channel
, cmd
, sizeof(char) * strlen(cmd
));
208 [self readChannel
:channel
];
210 // remove our temp file
211 cmd
= "rm -f __bu_print_drop__.pdf\r\n\0";
212 libssh2_channel_write(channel
, cmd
, sizeof(char) * strlen(cmd
));
213 [self readChannel
:channel
];
215 [self setStatus
:@
"Printed!" isError
:NO
];
217 libssh2_channel_send_eof(channel
);
218 libssh2_channel_eof(channel
);
219 libssh2_channel_close(channel
);
224 libssh2_channel_free(channel
);
227 libssh2_session_disconnect(ssh
, "Normal disconnect.");
228 libssh2_session_free(ssh
);
232 [progress stopAnimation
:self];