I'm building a jailbreak app in which it allows deb installs.
I'm stuck on showing the output or install process in another view controller, similar to iFile and Cydia's own installer.
Does anybody know how to get this to show?
What I have so far is a table view, tap file, action sheet pops up asking to install. Pressing install starts the install process and also opens another blank UIView. How would I pass that data to the opened view?
UPDATE 1 as requested:
Code for installing deb and pushing new view controller to display output:
//Deb file extension
NSString *debFileExtension = [fileName pathExtension];
NSLog(#"fileExtension is: %#", externalFileExtension);
NSSet *supportedFileExtensions = [NSSet setWithObjects:#"deb", nil];
if ([supportedFileExtensions containsObject:[debFileExtension lowercaseString]]) {
documentController = nil;
NSString *actionSheetTitle = fileName;
BlockActionSheet *sheet = [BlockActionSheet sheetWithTitle:actionSheetTitle];
[sheet addButtonWithTitle:#"Install" block:^{
NSString *appsyncDebPath = [path stringByAppendingPathComponent:fileName];
NSString *cmdString=[NSString stringWithFormat:#"/usr/bin/dpkg -i %#",appsyncDebPath];
const char *cmdChar=[cmdString UTF8String];
system(cmdChar);
DebViewController * vc = [[DebViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
[vc release];
NSLog(#"Install pressed %#", cmdString);
}];
[sheet setDestructiveButtonWithTitle:#"Cancel" block:nil];
[sheet showInView:self.view];
}
From that the DebViewController gets called. The issue is the displaying of the output or log or w/e in the new view.
Would a regular UIView work? Or do I need a specific view to receive it?
UPDATE 2: with suggested NSTask.
NSTask *task1 = [[NSTask alloc] init];
NSPipe *pipe1 = [NSPipe pipe];
[task1 setLaunchPath: #"/usr/bin/dpkg"];
[task1 setArguments: [NSArray arrayWithObjects: #"-i", nil]];
[task1 setStandardOutput: pipe1];
[task1 launch];
NSFileHandle *file = [pipe1 fileHandleForReading];
NSData * data = [file readDataToEndOfFile];
NSString * string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"Result: %#", string);
UITextView *txtview = [[UITextView alloc]initWithFrame:CGRectMake(0, 20, self.view.bounds.size.width, self.view.bounds.size.height)];
txtview.text = string;
//some other setup like setting the font for the UITextView...
[txtview sizeToFit];
[self.view addSubview:txtview];
UPDATE 3:
Everything is working!! Minus 1 thing.
NSString *debPath = [path stringByAppendingPathComponent:fileName];
NSTask *task1 = [[NSTask alloc] init];
NSPipe *pipe1 = [NSPipe pipe];
[task1 setLaunchPath: #"/Applications/myapp.app/"];
[task1 setArguments: [NSArray arrayWithObjects: #"/usr/bin/dpkg", #"-i", debPath, nil]];
[task1 setStandardOutput: pipe1];
[task1 launch];
NSFileHandle *file = [pipe1 fileHandleForReading];
NSData * data = [file readDataToEndOfFile];
OutputViewController * debOutput = [[OutputViewController alloc] init];
UINavigationController *vc = [[UINavigationController alloc] initWithRootViewController:debOutput];
[self.navigationController presentViewController:vc animated:YES completion:nil];
debOutput.output = [[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding];
So the provided code above works as it should, and the receiving view controller displays the output.
Only thing is, that it's not displaying the full output of the deb install. almost like its shorting the lines. I have the output set up as follows:
UITextView *l = [[UITextView alloc] initWithFrame:CGRectMake(5, 0, self.view.frame.size.width-5, self.view.frame.size.height)];
l.editable = NO;
l.textAlignment = NSTextAlignmentLeft;
l.font=[UIFont boldSystemFontOfSize:14];
l.textColor = [UIColor whiteColor];
l.backgroundColor = [UIColor colorWithWhite:0.1f alpha:1.0f];
l.text = [NSString stringWithFormat: #"%#", output];
l.textContainer.lineBreakMode = NSLineBreakByWordWrapping;
[l release];
UPDATE 4:
So what I ended up doing was loading some text in the viewDidLoad when the view first showed:
NSString *cmd0 = #"Running Debian Packager";
NSString *cmd1 = #"Executing Command: /usr/bin/dpkg -i";
NSString *cmd2 = #"Preparing - ";
NSString *cmd3 = #"Installing......Please wait...";
l.text = [NSString stringWithFormat:#"%#\n\n%#\n\n%#%#\n\n%#", cmd0, cmd1, cmd2, fileName, cmd3];
l.textContainer.lineBreakMode = NSLineBreakByWordWrapping;
[view addSubview:l];
Then called the deb install process in the viewDidAppear, which replaces the above code with the output:
//NSTask
NSString *debPath = [path stringByAppendingPathComponent:vc.fileName1];
NSTask *task1 = [[[NSTask alloc] init] autorelease];
NSPipe *pipe1 = [NSPipe pipe];
[task1 setLaunchPath: #"/Applications/myapp.app/process"];
[task1 setArguments: [NSArray arrayWithObjects:#"/usr/bin/dpkg", #"-i", debPath, #"2>/tmp/dpkg.log" ,nil]];
[task1 setStandardOutput: pipe1];
[task1 launch];
NSFileHandle *file = [pipe1 fileHandleForReading];
NSData *data = [file readDataToEndOfFile];
NSString *string = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
NSString *cmd3 = #"Success";
NSString *cmd4 = #"*If this package requires a respring, please do so above*";
NSString *dependencies = #"*You are seeing this message because this package requires the additional dependencies listed above*";
NSString *closeCydia = #"*If you are seeing this message, Cydia is probably open. Please close, and try to install the package again*";
//DPKG LOG FILE
NSError *error;
NSString *logPath = [NSString stringWithFormat:#"/tmp"];
NSString *dpkgLogFile = [logPath stringByAppendingPathComponent:#"dpkg.log"];
NSString *logContents = [NSString stringWithContentsOfFile:dpkgLogFile encoding:NSUTF8StringEncoding error:&error];
NSString *dependsString = #"dpkg: dependency problems";
NSString *lockString = #"dpkg: status database area is locked by another process";
if ([logContents containsString:lockString]) {
l.text = [NSString stringWithFormat:#"%#\n%#", logContents, closeCydia];
self.navigationController.navigationBar.topItem.rightBarButtonItem = nil;
}else if ([logContents containsString:dependsString]){
l.text = [NSString stringWithFormat:#"%#\n%#\n%#", string, logContents, dependencies];
self.navigationController.navigationBar.topItem.rightBarButtonItem = nil;
}else{
l.text = [NSString stringWithFormat:#"%#\n%#%#\n\n%#", string, logContents, cmd3, cmd4];
}
[view addSubview:l];
Depending on what the deb installs, I customized the output, i.e. If it has depends, or if the process is locked because Cydia is open.
All in all I'm happy with the turnout. Thanks to Nate for the direction to use NSTask, worked like a charm.
The only thing to make it better is to have it print off or readout, similar to how Cydia goes through line by line.
Instead of using the system() command to run the dpkg command line, I would suggest using NSTask to run the command, which makes it easier to capture the output as a NSString. Once you have a string, you can copy it into a text view, or wherever you like.
NSTask is a private API on iOS, but it's public on OS X, so there's lots of documentation available. In order to use it in your project, just find a copy of the NSTask.h header and copy it into your project (and #import it, of course).
Here's an example of using NSTask to capture command line output in a UIApplication.
Or, another one.
If your install process may take a while, and you'd like your UI to be responsive while it's running, it would be a good idea to run the method that performs the task in the background (using GCD, for example), and then write the resulting string to your UIView (text field, etc.) back on the main/UI thread.
Related
I am facing difficulties on passing a value on array for sectioned UITableView
This code works well for me
LandingMenu *landing0 = [[LandingMenu alloc]init];
[landing0 setMenuTitle:#"For Verification"];
[landing0 setMenuTotalCount:[NSString stringWithFormat:#"%i",20]];
[landing0 setMenuColorCode:[NSNumber numberWithInt:0]];
LandingMenu *landing6 = [[LandingMenu alloc]init];
[landing6 setMenuTitle:#"For Approval"];
[landing6 setMenuTotalCount:[NSString stringWithFormat:#"%i",5]];
[landing6 setMenuColorCode:[NSNumber numberWithInt:0]];
_taskList = [NSMutableArray arrayWithObjects:landing0, landing6, nil];
LandingMenu *landing1 = [[LandingMenu alloc]init];
[landing1 setMenuTitle:#"Fund Transfer Own"];
[landing1 setMenuTotalCount:[NSString stringWithFormat:#"%i",9]];
[landing1 setMenuType:[NSNumber numberWithInt:0]];
LandingMenu *landing2 = [[LandingMenu alloc]init];
[landing2 setMenuTitle:#"Fund Transfer Third Party"];
[landing2 setMenuTotalCount:[NSString stringWithFormat:#"%i",5]];
[landing2 setMenuType:[NSNumber numberWithInt:0]];
LandingMenu *landing3 = [[LandingMenu alloc]init];
[landing3 setMenuTitle:#"Checkbook Reorder"];
[landing3 setMenuTotalCount:[NSString stringWithFormat:#"%i",5]];
[landing3 setMenuType:[NSNumber numberWithInt:1]];
LandingMenu *landing4 = [[LandingMenu alloc]init];
[landing4 setMenuTitle:#"Stop Payment Order"];
[landing4 setMenuTotalCount:[NSString stringWithFormat:#"%i",6]];
[landing4 setMenuType:[NSNumber numberWithInt:0]];
_forVerificationList = [NSMutableArray arrayWithObjects:landing1, landing2, landing4, nil];
_forApprovalList = [NSMutableArray arrayWithObjects:landing3, nil];
[_menuList addObject:[[NSArray alloc] initWithObjects:landing1, landing2, landing4, nil]];
[_menuList addObject:[[NSArray alloc] initWithObjects:landing3, nil]];
Now, i'm having a problem how to convert something like the one specified above having output. Assuming that this code came from a JSON object.
for (NSDictionary *dictCQ in taskJson) {
NSLog(#"TASKLIST: %#", [dictCQ objectForKey:#"foTaskListModelWs"]);
NSDictionary *datadic = [dictCQ objectForKey:#"foTaskListModelWs"];
TaskList *task = [[TaskList alloc]init];
[task setCount:datadic[#"count"]];
[task setFuncCd:datadic[#"funcCd"]];
[task setFuncCdDscp:datadic[#"funcCdDscp"]];
[task setRequestStatus:datadic[#"requestStatus"]];
[task setRole:datadic[#"role"]];
[taskList addObject:task];
}
I am trying to send an HTML email from my SKPSMTP code in iOS. Right now, I'm just sending plain text, but I'm trying to upgrade that a little. I've included that code below.
I can't find any documentation. How can I upload an HTML file and include that as it's body. Also, there's an image that's being loaded from the same directory as the HTML file, if that makes a difference in the answer. Thanks.
NSMutableString *emailBody = [NSMutableString stringWithFormat:#"Here's your code again, "];
[emailBody appendString:userCode];
SKPSMTPMessage *email = [[SKPSMTPMessage alloc] init];
email.fromEmail = #"me#gmail.com";
NSString *toEmail = [NSString stringWithFormat:#"%#", self.loginInput.text];
email.toEmail = toEmail;
email.relayHost = #"smtp.gmail.com";
email.requiresAuth = YES;
email.login = #"me#gmail.com";
email.pass = #"myPass";
email.subject = #"Your Validation Code";
email.wantsSecure = YES;
email.delegate = self;
NSDictionary *plainPart = [NSDictionary dictionaryWithObjectsAndKeys:#"text/plain",kSKPSMTPPartContentTypeKey,
emailBody,kSKPSMTPPartMessageKey,#"8bit",kSKPSMTPPartContentTransferEncodingKey, nil];
email.parts = [NSArray arrayWithObjects:plainPart, nil];
// Send it!
[email send];
So, here's the answer I came across, just so everyone else can get the benefit of me struggling through:
//Send them an e-mail
NSError* error = nil;
NSString *path = [[NSBundle mainBundle] pathForResource: #"loginEmail" ofType: #"html"];
NSString *result = [NSString stringWithContentsOfFile: path encoding:
NSUTF8StringEncoding error: &error];
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"<!--INJECT CODE HERE -->"
options:0
error:&error];
NSString *emailBody = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:code];
NSLog(#"%#", [emailBody class]);
SKPSMTPMessage *email = [[SKPSMTPMessage alloc] init];
email.fromEmail = #"myemail#gmail.com";
NSString *toEmail = [NSString stringWithFormat:#"%#", self.loginInput.text];
email.toEmail = toEmail;
email.relayHost = #"smtp.gmail.com";
email.requiresAuth = YES;
email.login = #"myemail#gmail.com";
email.pass = #"myPass"
email.subject = #"Your Validation Code";
email.wantsSecure = YES;
email.delegate = self;
NSDictionary *htmlPart = [NSDictionary dictionaryWithObjectsAndKeys:#"text/html",kSKPSMTPPartContentTypeKey, emailBody,kSKPSMTPPartMessageKey,#"8bit",kSKPSMTPPartContentTransferEncodingKey, nil];
email.parts = [NSArray arrayWithObjects:htmlPart, nil];
// Send it!
NSLog(#"ABOUT TO SEND");
[email send];
So, I had to write an HTML file, host all my images on tinypic to include in the HTML, write some text to regex switch out my code variable, load in it in here and attach it as the part of my email with key "text/html". This code works, but if anyone has any other suggestions that are helpful, I'm willing to mark them as the right answer!
I'm trying to learn objective-c (I'm very new to that) and I have issues with memory management...
I'm developing an iPad app that uses TouchXML.
I've created my class that extends CXMLDocument and does some initialisation by reading some contents and saving into properties.
Here is my code (SimpleManifest.h):
#interface SimpleManifest : CXMLDocument {
CXMLNode *_defaultOrganization;
NSString *_title;
NSDictionary *dictionary;
}
#property (readonly) CXMLNode *defaultOrganization;
#property (readonly) NSString* title;
- (id) initWithPath:(NSString *)path options:(NSUInteger)options error:(NSError **)error;
#end
(SimpleManifest.m):
#import "SimpleManifest.h"
#import "CXMLNode_XPathExtensions.h"
#implementation SimpleManifest
- (id) initWithPath:(NSString *)path options:(NSUInteger)options error:(NSError **)error
{
/*
NSURL *theURL = [[[NSURL alloc] initFileURLWithPath:path] autorelease];
self = [self initWithContentsOfURL:theURL options:options error:error];
*/
NSData *data = [NSData dataWithContentsOfFile:path];
NSString *s = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
self = [self initWithXMLString:s options:options error:error];
if (self==nil) return nil;
// load main props
dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
#"http://www.imsglobal.org/xsd/imscp_v1p1", #"imscp",
#"http://ltsc.ieee.org/xsd/LOM", #"lom", nil];
// defualt organization
#try {
CXMLNode *orgsElem = [[[self childAtIndex:0] nodesForXPath:#"//imscp:organizations" namespaceMappings:dictionary error:nil] objectAtIndex:0];
NSString *xpath = [NSString stringWithFormat:#"//imscp:organization[#identifier='%#']", [[orgsElem attributeForName:#"default"] stringValue]];
_defaultOrganization = [[[self childAtIndex:0] nodesForXPath:xpath namespaceMappings:dictionary error:nil] objectAtIndex:0];
/*
NSArray *nodes = [[self childAtIndex:0] nodesForXPath:#"//imscp:organizations" namespaceMappings:dictionary error:nil];
NSString *xpath = [NSString stringWithFormat:#"//imscp:organization[#identifier='%#']", [[[nodes objectAtIndex:0] attributeForName:#"default"] stringValue]];
_defaultOrganization = [[[self childAtIndex:0] nodesForXPath:xpath namespaceMappings:dictionary error:nil] objectAtIndex:0];
*/
CXMLNode *titleElem = [[[self childAtIndex:0]
nodesForXPath:#"//lom:general/lom:title/lom:string"
namespaceMappings:dictionary
error:nil] objectAtIndex:0];
_title = [[titleElem stringValue] copy];
} #catch (NSException * e){
self = nil;
return nil;
}
return self;
}
#end
Later on in another class I do:
- (BOOL) isValidSCORMLesson:(NSString*) path {
NSString *manifPath = [path stringByAppendingPathComponent:#"imsmanifest.xml"];
if (![[NSFileManager defaultManager] fileExistsAtPath: manifPath isDirectory: NO])
return NO;
SimpleManifest *manifest = [[[SimpleManifest alloc] initWithPath:manifPath options:0 error:nil] autorelease];
NSLog(#"%#", manifest.defaultOrganization);
NSLog(#"%#", manifest.title);
return (manifest!=nil);
}
It gives me tons of "pointer being freed was not allocated" errors...
The thing changes if I comment out the NSLog calls above or just log the manifest.title property.
Project is not using ARC, so I'm sure I'm doing something wrong with memory management.
Can someone please help me understand where I'm doing wrong? Thanks!
There isn't anything obviously wrong with that code that would cause malloc errors. Best guess is that there is a bug in the CXMLDocument class/library or some mistake in the way you are using it.
Note that a "pointer being freed was not allocated" means that someone called free() (or dealloc, effectively) on a pointer to a piece of memory that was not allocated in the first place. It usually gives you a breakpoint you can set that will then give you a backtrace of exactly where it happened.
Some comments:
(1) Do not #try/#catch in that fashion. Just don't catch at all. The pattern you are using will hide any errors. Exceptions are not meant to be recoverable in iOS/Cocoa.
(2) You can create an NSString instance directly from a file; no need to load via NSData first.
(3) You should use ARC.
Sorry if this is elementary. Banging my head over it. My app works fine in iOS5.1 and below, but fails to reach my .txt files in my Supporting Files folder in ios6. It always returns "null". I researched this and have checked the Bundle, all is there. The table lists about 8 speakers. On click, it is supposed to pull a DetailView loaded from a .txt file.
...[code]...
else if (self.makeLabel.text == #"Peter Sengenberger") {
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"sengenberger" ofType:#"txt"];
if (filePath) {
NSString *myText1 = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding error:nil];
if (myText1) {
textData= [[UITextView alloc] initWithFrame:CGRectMake(5,0, 280,200)]; //size.height-30 )];
textData.text = myText1;
[textData setFont:[UIFont systemFontOfSize:14]];
[textData setBackgroundColor:[UIColor clearColor]];
[textData setTextColor:[UIColor blackColor]];
textData.editable = NO;
textData.dataDetectorTypes = UIDataDetectorTypeLink;
[textScroll addSubview:textData];
}
}
} // end if
Thanks for any help!
I have tested the code for sending attachments using this useful library:
Skpsmtpmessage library
The email seems to get sent correctly, and when I view it through hotmail or gmail clients I see the jpeg image. However, when I view this same email through an iOS mail client, the attachment appears as a "contact" and clicking on this gives me the option to save the file as a new contact.
I have tried sending an email with jpeg attachment from hotmail, and when I do this it appears correctly in the iOS client.
Does anyone know whether this is the code or iOS getting it wrong?
//the guts of the message.
SKPSMTPMessage *testMsg = [[SKPSMTPMessage alloc] init];
testMsg.fromEmail = #"aname#gmail.com";
testMsg.toEmail = #"aname#gmail.com";
testMsg.relayHost = #"smtp.gmail.com";
testMsg.requiresAuth = YES;
testMsg.login = #"aname#gmail.com";
testMsg.pass = #"password";
testMsg.subject = #"The message subject";
testMsg.wantsSecure = YES; // smtp.gmail.com doesn't work without TLS!
// Only do this for self-signed certs!
// testMsg.validateSSLChain = NO;
testMsg.delegate = self;
//email contents
NSDate* now = [NSDate date];
NSString * bodyMessage = [NSString stringWithFormat:#"The message body"];
// email image if it exists
NSString *jpgPath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/file.jpeg"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSMutableArray* parts = [[NSMutableArray alloc] init];
// add plain part
NSDictionary *plainPart = [NSDictionary dictionaryWithObjectsAndKeys:#"text/plain",kSKPSMTPPartContentTypeKey,
bodyMessage ,kSKPSMTPPartMessageKey,#"8bit",kSKPSMTPPartContentTransferEncodingKey,nil];
[parts addObject: plainPart];
// add attachments
NSData *attachmentData = [NSData dataWithContentsOfFile:jpgPath];
NSString *directory = #"text/directory;\r\n\tx-unix-mode=0644;\r\n\tname=\"file.jpeg\"";
NSString *attachment = #"attachment;\r\n\tfilename=\"file.jpeg\"";
NSDictionary *image_part = [NSDictionary dictionaryWithObjectsAndKeys:
directory,kSKPSMTPPartContentTypeKey,
attachment,kSKPSMTPPartContentDispositionKey,
[attachmentData encodeBase64ForData],kSKPSMTPPartMessageKey,
#"base64",kSKPSMTPPartContentTransferEncodingKey,nil];
[parts addObject: image_part];
testMsg.parts = parts;
[testMsg send];
Try to change
NSString *directory = #"text/directory;...
to
NSString *directory = #"text/jpeg;...
I hope this works for you!
Steffen