Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / editors / scapp / iPhone / FileBrowserViewController.mm
blob78d5eccaeacb0fcab06c81d2bbe2f63b8089589a
1 //
2 //  FileBrowserViewController.m
3 //  iscsynth
4 //
5 //  Created by Axel Balley on 26/10/08.
6 //  Copyright 2008 __MyCompanyName__. All rights reserved.
7 //
9 #import "FileBrowserViewController.h"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <pthread.h>
14 #include <sys/socket.h>
15 #include <sys/types.h>
16 #include <fcntl.h>
17 #include <netdb.h>
18 #include <unistd.h>
19 #include <string.h>
22 #define FILETRANSFER_PORT       15000
24 struct Header
26         int bytes;
27         int name_len;
30 @implementation FileTransferController
32 - (id) initWithNibName:(NSString *)name bundle:(NSBundle *)bundle browser:(FileBrowserViewController *)b
34         if (self=[super initWithNibName:name bundle:bundle])
35         {
36                 browser = b;
37                 service = [[NSNetService alloc] initWithDomain:@"local." type:@"_sctransfer._tcp" name:@"SuperCollider" port:FILETRANSFER_PORT];
38                 thread = 0;
40                 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
42                 int val = 1;
43                 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)))
44                 {
45                         printf("couldn't set option\n");
46                         return 0;
47                 }
48                 
49                 struct sockaddr_in addr;
50                 memset(&addr, 0, sizeof(addr));
51                 addr.sin_family = AF_INET;
52                 addr.sin_addr.s_addr = htonl(INADDR_ANY);
53                 addr.sin_port = htons(FILETRANSFER_PORT);
54                 
55                 if (bind(sock, (sockaddr *) &addr, sizeof(addr)))
56                 {
57                         printf("couldn't bind !\n");
58                         shutdown(sock, 0);
59                         sock = 0;
60                         return self;
61                 }
63                 if (listen(sock, 1))
64                 {
65                         printf("couldn't listen\n");
66                         shutdown(sock, 0);
67                         sock = 0;
68                         return self;
69                 }               
70         }
71         return self;
74 - (void) close:(id)sender
76         [browser closeListen];
79 - (void) viewDidLoad
81         [label setText:@"Waiting for connection..."];
82         [progress setProgress:0.f];
83         [self start];   
86 - (void) viewWillDisappear:(BOOL)animated
88         [self stop];
91 - (void) start
93         [service publish];
94         
95         if (thread) return;
96         
97         run_thread = 1;
98         thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadProc:) object:nil];
99         [thread start]; 
102 - (void) stop
104         [service stop];
105         //[thread stop];
106         run_thread = 0;
107         [thread release];
108         thread = 0;
109         shutdown(sock, 0);
112 - (void) threadProc:(id)arg
114         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
115         
116         struct sockaddr_in their_addr;
117         int len = sizeof(their_addr);
118         
119         while (run_thread)
120         {
121                 usleep(1000);
122                 
123                 fd_set readfs;
124                 FD_ZERO(&readfs);
125                 FD_SET(sock, &readfs);
126                 struct timeval t;
127                 t.tv_sec = 0;
128                 t.tv_usec = 100000;
129                 if (select(sock+1, &readfs, 0, 0, &t)<=0) continue;
130                 
131                 int connection_sock = accept(sock, (sockaddr *) &their_addr, (socklen_t *) &len);
132                 if (connection_sock<0)
133                 {
134                         continue;
135                 }
136                 
137                 [self performSelectorOnMainThread:@selector(updateLabel:) withObject:@"Connected..." waitUntilDone:NO];
138                 
139                 Header h;
140                 int ret = recvfrom(connection_sock, &h, sizeof(h), 0, (sockaddr *) &their_addr, (socklen_t *) &len);
141                 if (ret!=sizeof(h))
142                 {
143                         printf("failed receiving header\n");
144                         shutdown(connection_sock, 0);
145                         continue;
146                 }
147                 
148                 int size = htonl(h.bytes);
149                 int name_len = htonl(h.name_len);
150                 
151                 if (!size || !name_len)
152                 {
153                         shutdown(connection_sock, 0);
154                         continue;
155                 }
156                 
157                 char *name = (char *) malloc(name_len+1);
158                 ret = recvfrom(connection_sock, name, name_len+1, 0, (sockaddr *) &their_addr, (socklen_t *) &len);
159                 if (ret!=name_len+1)
160                 {
161                         shutdown(connection_sock, 0);
162                         continue;
163                 }
164                 
165                 [self performSelectorOnMainThread:@selector(updateLabel:) withObject:[NSString stringWithFormat:@"Receiving %s...", name] waitUntilDone:NO];
166                 [self performSelectorOnMainThread:@selector(updateProgress:) withObject:[NSNumber numberWithFloat:0.f] waitUntilDone:NO];
168                 char *buf = (char *) malloc(size);
169                 int read = 0;
170                 
171                 while (read<size)
172                 {
173                         int ret = recvfrom(connection_sock, buf+read, size-read, 0, (sockaddr *) &their_addr, (socklen_t *) &len);
174                         if (ret<=0)
175                         {
176                                 printf("failed receiving !");
177                                 shutdown(connection_sock, 0);
178                                 continue;
179                         }
180                         read += ret;
181                         [self performSelectorOnMainThread:@selector(updateProgress:) withObject:[NSNumber numberWithFloat:(float)(read/size)*0.5f] waitUntilDone:NO];
182                 }
184                 char output[512];
185                 output[0] = 0;
186                 
187                 NSString *path = [browser path];
188                 if (path)
189                 {
190                         strcpy(output, [path UTF8String]);
191                         strcat(output, "/");
192                 }
193                 strcat(output, name);
194                 
195                 FILE *f = fopen(output, "w");
196                 int written = 0;
197                 while (written<size)
198                 {
199                         int ret = fwrite(buf, 1, size-written, f);
200                         written += ret;
201                         buf += ret;
202                         [self performSelectorOnMainThread:@selector(updateProgress:) withObject:[NSNumber numberWithFloat:(float)(written/size)+0.5f] waitUntilDone:NO];
203                 }
204                 fclose(f);
205                 
206                 [self performSelectorOnMainThread:@selector(updateLabel:) withObject:[NSString stringWithFormat:@"Received %s", name] waitUntilDone:NO];
207         }
208         
209         printf("bye bye !\n");
210         
211         [pool release];
214 - (void) updateLabel:(NSString *)string
216         [label setText:string];
219 - (void) updateProgress:(NSNumber *)val
221         [progress setProgress:[val floatValue]];
224 - (void) dealloc
226         [service release];
227         [super dealloc];
229 @end
233 @implementation FileBrowserViewController
235 - (id)initWithCoder:(NSCoder *)decoder
237     if (self = [super initWithCoder:decoder])
238         {
239                 target = 0;
240                 selector = 0;
241                 [self setup];
242         }
243     return self;
246 - (id) initWithNibName:(NSString *)name bundle:(NSBundle *)bundle
248     if (self = [super initWithNibName:name bundle:bundle])
249         {
250                 target = 0;
251                 selector = 0;
252                 [self setup];
253         }
254     return self;
257 - (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
259         return YES;
262 - (void) setup
264         FileBrowserPageViewController *m = [[FileBrowserPageViewController alloc] initWithNibName:@"SuperCollider_BrowserPage" bundle:nil];
265         [self pushViewController:m animated:NO];
266         [m release];
269 - (void) setPath:(NSString *)p
271         FileBrowserPageViewController *m = (FileBrowserPageViewController *) [self.viewControllers objectAtIndex:0];
272         if (m)
273         {
274                 [m setPath:p];
275                 m.title = @"Documents";
276         }
279 - (void) setTarget:(id)t withSelector:(SEL)s
281         target = [t retain];
282         selector = s;
285 - (void) didSelect:(NSString *) path
287         if (target && [target respondsToSelector:selector]) [target performSelector:selector withObject:path];
290 - (void) dealloc
292         if (target) [target release];
293         [super dealloc];
296 @end
298 @implementation FileBrowserPageViewController
300 - (id) initWithNibName:(NSString *)name bundle:(NSBundle *)bundle
302     if (self = [super initWithNibName:name bundle:bundle])
303         {
304                 array = 0;
305                 path = 0;
306         }
307     return self;
310 - (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
312         return YES;
315 - (void) setPath:(NSString *)p
317         if (path) [path release];
318         path = [p retain];
320         self.title = [path lastPathComponent];
321         
322         [self refresh];
325 - (void) viewDidLoad
327         self.navigationItem.rightBarButtonItem = refreshButton;
328         
329         [self refresh];
332 - (void) refresh
334         if (!path) return;
335         if (array) [array release];
336         array = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil] retain];
337                 
338         [table reloadData];
341 - (void) triggerRefresh:(id)sender
343         [self refresh];
346 - (void) flashScrollIndicators
348         [table flashScrollIndicators];
351 - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
353         return [array count];
356 - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
358         UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyCell"];
359         if (!cell)
360         {
361                 cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"MyCell"] autorelease];
362         }
363         NSString *item = (NSString *)[array objectAtIndex:indexPath.row];
364         [cell setText:item];
365         NSString *fullpath = [path stringByAppendingPathComponent:item];
366         NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:fullpath error:nil];
367         if ([attributes objectForKey:NSFileType]==NSFileTypeDirectory)
368         {
369                 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
370         }
371         else cell.accessoryType = UITableViewCellAccessoryNone;
372         return cell;
375 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)newIndexPath
377         NSString *fullpath = [path stringByAppendingPathComponent:[array objectAtIndex:newIndexPath.row]];
378         
379         NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:fullpath error:nil];
380         if ([attributes objectForKey:NSFileType]==NSFileTypeDirectory)
381         {
382                 [tableView deselectRowAtIndexPath:newIndexPath animated:NO];
383                 FileBrowserPageViewController *c = [[FileBrowserPageViewController alloc] initWithNibName:@"SuperCollider_BrowserPage" bundle:nil];
384                 [c setPath:fullpath];
385                 [self.navigationController pushViewController:c animated:YES];
386                 [c release];
387                 return;
388         }
389         
390         [tableView deselectRowAtIndexPath:newIndexPath animated:YES];
391         [(FileBrowserViewController *) self.navigationController didSelect:fullpath];
394 - (void)dealloc
396         if (path) [path release];
397         if (array) [array release];
398         
399     [super dealloc];
403 @end