summaryrefslogtreecommitdiffabout
path: root/pumpkin/ARequest.m
Unidiff
Diffstat (limited to 'pumpkin/ARequest.m') (more/less context) (ignore whitespace changes)
-rw-r--r--pumpkin/ARequest.m184
1 files changed, 184 insertions, 0 deletions
diff --git a/pumpkin/ARequest.m b/pumpkin/ARequest.m
new file mode 100644
index 0000000..439366e
--- a/dev/null
+++ b/pumpkin/ARequest.m
@@ -0,0 +1,184 @@
1
2#import "pumpkin.h"
3#import "ARequest.h"
4#import "ReceiveXFer.h"
5#import "SendXFer.h"
6
7static void cbHost(CFHostRef h,CFHostInfoType hi,const CFStreamError *e,void *i) {
8 [(ARequest*)i hostCallbackWithHost:h info:hi andError:e];
9}
10
11
12@implementation ARequest
13@synthesize requestIsGet;
14@synthesize doTouchMe;
15@synthesize statusLabel;
16@synthesize errorLabel;
17
18@synthesize localFile;
19@synthesize remoteHost;
20@synthesize remotePort;
21@synthesize remoteFile;
22@synthesize xferType;
23@synthesize blockSize;
24@synthesize timeout;
25
26@synthesize remoteHostBox;
27
28-(void)unhost {
29 if(!cfhost) return;
30 CFHostCancelInfoResolution(cfhost, kCFHostAddresses);
31 CFHostUnscheduleFromRunLoop(cfhost, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
32 CFRelease(cfhost);
33 cfhost = nil;
34}
35-(void)loadDefaults {
36 id d = [NSUserDefaultsController.sharedUserDefaultsController values];
37 self.remotePort = [d valueForKey:@"remotePort"];
38 self.blockSize = [d valueForKey:@"blockSize"];
39 self.xferType = [d valueForKey:@"xferType"];
40 self.remoteHost = [d valueForKey:@"remoteHost"];
41 self.timeout = [d valueForKey:@"timeout"];
42
43 self.localFile = [[d valueForKey:@"tftpRoot"] stringByAppendingString:@"/"];
44}
45-(void)saveDefaults {
46 NSUserDefaultsController *dc = [NSUserDefaultsController sharedUserDefaultsController];
47 id d = dc.values;
48 [d setValue:self.remotePort forKey:@"remotePort"];
49 [d setValue:self.remoteHost forKey:@"remoteHost"];
50 [d setValue:self.blockSize forKey:@"blockSize"];
51 [d setValue:self.xferType forKey:@"xferType"];
52 [d setValue:self.timeout forKey:@"timeout"];
53 [dc save:self];
54}
55
56
57- (IBAction)startXfer:(id)sender {
58 if(!(cfhost = CFHostCreateWithName(kCFAllocatorDefault, (CFStringRef)remoteHost))) {
59 self.errorLabel = @"failed to even try to resolve.";
60 return;
61 }
62 struct CFHostClientContext hc;
63 hc.version=0; hc.info=self; hc.retain=0;hc.release=0;
64 hc.copyDescription=0;
65 CFHostSetClient(cfhost, cbHost, &hc);
66 CFHostScheduleWithRunLoop(cfhost, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
67 CFStreamError e;
68 if(!CFHostStartInfoResolution(cfhost, kCFHostAddresses, &e)) {
69 self.errorLabel = @"failed to start host resolution.";
70 [self unhost];
71 return;
72 }
73 self.statusLabel = @"resolving remote host…";
74 self.doTouchMe = NO;
75}
76
77-(void)hostCallbackWithHost:(CFHostRef)h info:(CFHostInfoType)hi andError:(const CFStreamError *)e {
78 NSString *el = nil;
79 CFArrayRef aa = nil;
80 __block struct sockaddr_in peer;
81 do {
82 if(e && (e->domain || e->error)) {
83 el=@"failed to resolve remote address"; break;
84 }
85 Boolean hbr;
86 aa = CFHostGetAddressing(cfhost, &hbr);
87 if(!(hbr && aa && CFArrayGetCount(aa))) {
88 el=@"failed to find remote address"; break;
89 }
90 peer.sin_addr.s_addr=INADDR_NONE; [(NSArray*)aa enumerateObjectsUsingBlock:^(NSData *o,NSUInteger i,BOOL *s) {
91 const struct sockaddr_in *sin = o.bytes;
92 if(sin->sin_family!=AF_INET) return;
93 memmove(&peer,sin,sizeof(peer));
94 *s = YES;
95 }];
96 if(peer.sin_addr.s_addr==INADDR_NONE) {
97 el=@"found no ipv4 address"; break;
98 }
99 peer.sin_port = htons([remotePort unsignedIntValue]);
100 }while(false);
101 [self unhost];
102 if(el) {
103 self.errorLabel = el; self.doTouchMe = YES; return;
104 }
105 [self saveDefaults];
106 [[[requestIsGet?ReceiveXFer.class:SendXFer.class alloc]
107 initWithLocalFile:localFile peerAddress:&peer remoteFile:remoteFile xferType:xferType blockSize:blockSize.unsignedIntValue andTimeout:timeout.intValue]
108 autorelease];
109 [self.window performClose:nil];
110}
111
112- (IBAction)pickFile:(id)sender {
113 NSSavePanel *p = nil;
114 if(requestIsGet) {
115 p = [NSSavePanel savePanel];
116 p.canCreateDirectories = YES;
117 }else{
118 NSOpenPanel *pp = [NSOpenPanel openPanel];
119 pp.canChooseDirectories = NO;
120 pp.canChooseFiles = YES;
121 pp.allowsMultipleSelection = NO;
122 p = pp;
123 }
124 p.prompt = @"Pick the local file";
125 if([p runModal]!=NSFileHandlingPanelOKButton) return;
126 self.localFile = p.URL.path;
127}
128
129- (ARequest*) initWithGet:(BOOL)gr {
130 if(!(self = [super initWithWindowNibName:@"ARequest"])) return self;
131 self.doTouchMe = YES;
132 cfhost = nil;
133 requestIsGet = gr;
134 if(requestIsGet) {
135 self.window.title = @"Get file from remote TFTP server";
136 self.window.initialFirstResponder = remoteHostBox;
137 }else{
138 self.window.title = @"Put file to remote TFTP server";
139 }
140 [self loadDefaults];
141 [self addObserver:self forKeyPath:@"localFile" options:0 context:0];
142 [self addObserver:self forKeyPath:@"remoteFile" options:0 context:0];
143 return [self retain];
144}
145-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
146 if(requestIsGet) {
147 if([keyPath isEqualToString:@"remoteFile"]) {
148 if(self.remoteFile.length) {
149 self.localFile= [([self.localFile hasSuffix:@"/"]
150 ?self.localFile
151 :[self.localFile stringByDeletingLastPathComponent])
152 stringByAppendingPathComponent:self.remoteFile.lastPathComponent];
153 }else
154 self.localFile=[[self.localFile stringByDeletingLastPathComponent] stringByAppendingString:@"/"];
155 }
156 }else{
157 if([keyPath isEqualToString:@"localFile"]) {
158 self.remoteFile=[self.localFile hasSuffix:@"/"]
159 ?@"":self.localFile.lastPathComponent;
160 }
161 }
162}
163
164+ (ARequest*) aRequestWithGet:(BOOL)gr {
165 return [[[ARequest alloc] initWithGet:gr] autorelease];
166}
167
168static void popMeUp(BOOL g) {
169 [[ARequest aRequestWithGet:g].window makeKeyAndOrderFront:nil];
170}
171+ (void)getFile { popMeUp(YES); }
172+ (void)putFile { popMeUp(NO); }
173
174- (void)windowDidLoad {
175}
176
177- (void)windowWillClose:(NSNotification*)n {
178 [self unhost];
179 [self removeObserver:self forKeyPath:@"localFile" context:0];
180 [self removeObserver:self forKeyPath:@"remoteFile" context:0];
181 [self release];
182}
183
184@end