/
Tweak.xm
404 lines (364 loc) · 15.1 KB
/
Tweak.xm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
#import "Interfaces.h"
#define kSettingsPath [NSHomeDirectory() stringByAppendingPathComponent:@"/Library/Preferences/com.phillipt.hermes.plist"]
#define dla(x, a) if(debug) NSLog(x, a)
#define dl(x) if(debug) NSLog(x)
CKIMMessage* sbMessage = [[%c(CKIMMessage) alloc] init];
BOOL isPending;
BOOL enabled;
//BOOL alertActive = NO;
BOOL debug = YES;
NSString* rawAddress;
NSString* reply;
UITextField* responseField;
BOOL pirated;
int appFrom;
NSMutableDictionary* prefs = [NSMutableDictionary dictionaryWithContentsOfFile:kSettingsPath];
@implementation GarbClass
//This code does not work on iOS 7. Apparantly, no references back to UIAlertView are kept in the keyWindow. Tl;Dr this code is useless, hence the 'isPending' variable. I'm leaving it here in case anyone wants to figure out how to make it work
-(BOOL)hasPendingAlert {
for (UIWindow* window in [UIApplication sharedApplication].windows){
for (UIView *subView in [window subviews]){
if ([subView isKindOfClass:[UIAlertView class]]) {
return YES;
}
else {
return NO;
}
}
}
for (UIWindow* window in [UIApplication sharedApplication].windows) {
NSArray* subviews = window.subviews;
if ([subviews count] > 0) {
BOOL alert = [[subviews objectAtIndex:0] isKindOfClass:[UIAlertView class]];
BOOL action = [[subviews objectAtIndex:0] isKindOfClass:[UIActionSheet class]];
if (alert || action)
return YES;
}
}
return NO;
}
-(UIAlertView*)createQRAlertWithType:(NSString*)type name:(NSString*)name text:(NSString*)text {
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:@"%@ from %@", type, name] message:[NSString stringWithFormat:@"\"%@\"", text] delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:@"Send", /*@"Open Messages",*/ nil];
[alert setAlertViewStyle:UIAlertViewStylePlainTextInput];
responseField = [alert textFieldAtIndex:0];
[alert textFieldAtIndex:0].autocapitalizationType = UITextAutocapitalizationTypeSentences;
[alert textFieldAtIndex:0].autocorrectionType = UITextAutocorrectionTypeYes;
[alert textFieldAtIndex:0].enablesReturnKeyAutomatically = YES;
[responseField setPlaceholder:@"Enter response here"];
alert.delegate = self;
if ([type isEqualToString:@"SMS"]) {
alert.tintColor = [UIColor greenColor];
}
else {
alert.tintColor = [UIColor blueColor];
}
return alert;
}
-(UIAlertView*)alertFromCKIMMessage:(CKIMMessage*)obj andType:(NSString*)type withPart:(CKTextMessagePart*)text {
UIAlertView* alert = [self createQRAlertWithType:type name:obj.sender.name text:text.text.string];
return alert;
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
notify_post("com.phillipt.hermes.doneResponding");
isPending = NO;
//alertActive = NO;
prefs = [NSMutableDictionary dictionaryWithContentsOfFile:kSettingsPath];
[(NSMutableDictionary*)prefs setObject:@NO forKey:@"alertActive"];
[(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:YES];
if (buttonIndex != [alertView cancelButtonIndex]) {
if (buttonIndex != 1) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms://"]];
}
else {
[(NSMutableDictionary*)prefs setObject:responseField.text forKey:@"reply"];
[(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:YES];
reply = responseField.text;
NSDictionary* responseInfoDict = @{
@"reply" : reply,
@"rawAddress" : prefs[@"rawAddress"]
};
[[UIApplication sharedApplication] launchApplicationWithIdentifier:@"com.apple.MobileSMS" suspended:YES];
[OBJCIPC sendMessageToAppWithIdentifier:@"com.apple.MobileSMS" messageName:@"com.phillipt.hermes.ipc" dictionary:responseInfoDict replyHandler:^(NSDictionary *response) {
dla(@"Received reply from MobileSMS: %@", response);
}];
}
}
else {
isPending = NO;
}
}
@end
@interface KikGarbClass : GarbClass <UIAlertViewDelegate>
@end
@implementation KikGarbClass
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
isPending = NO;
//alertActive = NO;
prefs = [NSMutableDictionary dictionaryWithContentsOfFile:kSettingsPath];
[(NSMutableDictionary*)prefs setObject:@NO forKey:@"alertActive"];
[(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:YES];
if (buttonIndex != [alertView cancelButtonIndex]) {
if (buttonIndex != 1) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"kik://"]];
}
else {
[(NSMutableDictionary*)prefs setObject:responseField.text forKey:@"reply"];
[(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:YES];
reply = responseField.text;
NSDictionary* responseInfoDict = @{
@"reply" : reply,
@"displayName" : prefs[@"displayName"],
@"jid" : prefs[@"jid"],
@"kikUser" : prefs[@"kikUser"]
};
[[UIApplication sharedApplication] launchApplicationWithIdentifier:@"com.kik.chat" suspended:YES];
[OBJCIPC sendMessageToAppWithIdentifier:@"com.kik.chat" messageName:@"com.phillipt.hermes.kik" dictionary:responseInfoDict replyHandler:^(NSDictionary *response) {
dla(@"Received reply from Kik: %@", response);
}];
}
}
else {
isPending = NO;
}
}
@end
@interface WhatsAppGarbClass : GarbClass <UIAlertViewDelegate>
@end
@implementation WhatsAppGarbClass
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
isPending = NO;
//alertActive = NO;
prefs = [NSMutableDictionary dictionaryWithContentsOfFile:kSettingsPath];
[(NSMutableDictionary*)prefs setObject:@NO forKey:@"alertActive"];
[(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:YES];
if (buttonIndex != [alertView cancelButtonIndex]) {
if (buttonIndex != 1) {
//[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"kik://"]];
}
else {
[(NSMutableDictionary*)prefs setObject:responseField.text forKey:@"reply"];
[(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:YES];
reply = responseField.text;
NSDictionary* responseInfoDict = @{
@"reply" : reply,
//@"displayName" : prefs[@"displayName"],
@"jid" : prefs[@"jid"],
//@"kikUser" : prefs[@"kikUser"]
};
[[UIApplication sharedApplication] launchApplicationWithIdentifier:@"net.whatsapp.WhatsApp" suspended:YES];
[OBJCIPC sendMessageToAppWithIdentifier:@"net.whatsapp.WhatsApp" messageName:@"com.phillipt.hermes.whatsapp" dictionary:responseInfoDict replyHandler:^(NSDictionary *response) {
dla(@"Received reply from WhatsApp: %@", response);
}];
}
}
else {
isPending = NO;
}
}
@end
GarbClass* garb = [[GarbClass alloc] init];
void loadPrefs() {
prefs = [NSMutableDictionary dictionaryWithContentsOfFile:kSettingsPath];
if ([prefs objectForKey:@"enabled"] == nil) enabled = NO;
else enabled = [[prefs objectForKey:@"enabled"] boolValue];
if (!enabled) {
dl(@"[Hermes3] Hermes shutting down :(");
}
else {
dl(@"[Hermes3] Hermes turning on");
}
}
%hook SpringBoard
-(void)applicationDidFinishLaunching:(id)application {
%orig;
loadPrefs();
prefs = [NSMutableDictionary dictionaryWithContentsOfFile:kSettingsPath];
[(NSMutableDictionary*)prefs setObject:@(enabled) forKey:@"enabled"];
if (!prefs) {
UIAlertView* firstRunAlert = [[UIAlertView alloc] initWithTitle:@"Hermes" message:@"Welcome to Hermes. To get started, visit Hermes's settings page." delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];
[firstRunAlert show];
}
[OBJCIPC registerIncomingMessageFromAppHandlerForMessageName:@"com.phillipt.hermes.kikMsgSend" handler:^NSDictionary *(NSDictionary *message) {
[(NSMutableDictionary*)prefs setObject:message[@"titleType"] forKey:@"titleType"];
[(NSMutableDictionary*)prefs setObject:message[@"displayName"] forKey:@"displayName"];
[(NSMutableDictionary*)prefs setObject:message[@"text"] forKey:@"text"];
[(NSMutableDictionary*)prefs setObject:message[@"jid"] forKey:@"jid"];
[(NSMutableDictionary*)prefs setObject:message[@"kikUser"] forKey:@"kikUser"];
if ([(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:YES]) {
dl(@"[Hermes3] Prefs wrote successfully");
}
else {
dl(@"[Hermes3] Prefs didn't write successfully D:");
}
return 0;
}];
[OBJCIPC registerIncomingMessageFromAppHandlerForMessageName:@"com.phillipt.hermes.WhatsAppMsgSend" handler:^NSDictionary *(NSDictionary *message) {
[(NSMutableDictionary*)prefs setObject:message[@"titleType"] forKey:@"titleType"];
[(NSMutableDictionary*)prefs setObject:message[@"displayName"] forKey:@"displayName"];
[(NSMutableDictionary*)prefs setObject:message[@"text"] forKey:@"text"];
[(NSMutableDictionary*)prefs setObject:message[@"responseJID"] forKey:@"jid"];
//[(NSMutableDictionary*)prefs setObject:message[@"kikUser"] forKey:@"kikUser"];
if ([(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:YES]) {
dl(@"[Hermes3] Prefs wrote successfully");
}
else {
dl(@"[Hermes3] Prefs didn't write successfully D:");
}
return 0;
}];
if ([(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:YES]) {
dl(@"[Hermes3] Prefs wrote successfully");
}
else {
dl(@"[Hermes3] Prefs didn't write successfully D:");
}
[[UIApplication sharedApplication] launchApplicationWithIdentifier:@"com.apple.MobileSMS" suspended:YES];
[[UIApplication sharedApplication] launchApplicationWithIdentifier:@"com.kik.chat" suspended:YES];
[[UIApplication sharedApplication] launchApplicationWithIdentifier:@"net.whatsapp.WhatsApp" suspended:YES];
//system("open /Applications/MobileSMS.app");
if (pirated) {
UIAlertView* pirateAlert = [[UIAlertView alloc] initWithTitle:@"Hermes" message:@"This version of Hermes has been pirated. Please consider purchasing a copy as it took a lot of work to create." delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];
[pirateAlert show];
}
}
%end
//(Yet another) hacky check to not show alerts while others are pending
%hook UIAlertView
- (void)show {
prefs = [NSMutableDictionary dictionaryWithContentsOfFile:kSettingsPath];
[(NSMutableDictionary*)prefs setObject:@YES forKey:@"alertActive"];
[(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:NO];
%orig;
}
-(void)dismiss {
prefs = [NSMutableDictionary dictionaryWithContentsOfFile:kSettingsPath];
[(NSMutableDictionary*)prefs setObject:@NO forKey:@"alertActive"];
[(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:NO];
%orig;
}
-(void)dismissWithClickedButtonIndex:(NSInteger)clickedButtonIndex animated:(BOOL)animated {
prefs = [NSMutableDictionary dictionaryWithContentsOfFile:kSettingsPath];
[(NSMutableDictionary*)prefs setObject:@NO forKey:@"alertActive"];
[(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:NO];
%orig;
}
-(void)dismissAnimated:(BOOL)animated {
prefs = [NSMutableDictionary dictionaryWithContentsOfFile:kSettingsPath];
[(NSMutableDictionary*)prefs setObject:@NO forKey:@"alertActive"];
[(NSMutableDictionary*)prefs writeToFile:kSettingsPath atomically:NO];
%orig;
}
%end
%hook BBBulletin
%new
-(BOOL)isHermesBulletin {
if ([[self sectionID] isEqualToString:@"com.apple.MobileSMS"] || [[self sectionID] isEqualToString:@"com.kik.chat"] || [[self sectionID] isEqualToString:@"net.whatsapp.WhatsApp"]) {
if ([[self sectionID] isEqualToString:@"com.apple.MobileSMS"]) {
[[UIApplication sharedApplication] launchApplicationWithIdentifier:@"com.apple.MobileSMS" suspended:YES];
appFrom = 1;
}
else if ([[self sectionID] isEqualToString:@"com.kik.chat"]) {
[[UIApplication sharedApplication] launchApplicationWithIdentifier:@"com.kik.chat" suspended:YES];
appFrom = 2;
}
else {
[[UIApplication sharedApplication] launchApplicationWithIdentifier:@"net.whatsapp.WhatsApp" suspended:YES];
appFrom = 3;
}
return YES;
}
return NO;
}
%end
UIButton *replyButton;
@interface SBAppSwitcherModel
- (id)sharedInstance;
- (NSArray *)identifiers;
@end
BOOL isAppRunning(int sender) {
for (NSString *identifier in [[%c(SBAppSwitcherModel) sharedInstance] identifiers]) {
if (sender == 1) {
if ([identifier isEqualToString:@"com.apple.MobileSMS"]) return YES;
}
else if (sender == 2) {
if ([identifier isEqualToString:@"com.kik.chat"]) return YES;
}
else if (sender == 3) {
if ([identifier isEqualToString:@"net.whatsapp.WhatsApp"]) return YES;
}
}
return NO;
}
BOOL shouldShowReply(int sender) {
prefs = [NSMutableDictionary dictionaryWithContentsOfFile:kSettingsPath];
if (!prefs) return NO;
if (sender == 1) {
if ([prefs[@"messagesUse"] boolValue] && isAppRunning(sender)) return YES;
}
else if (sender == 2) {
if ([prefs[@"kikUse"] boolValue] && isAppRunning(sender)) return YES;
}
else if (sender == 3) {
if ([prefs[@"whatsUse"] boolValue] && isAppRunning(sender)) return YES;
}
return NO;
}
%hook SBDefaultBannerView
%new
-(BBBulletin *)hermesBulletin {
return [[[self bannerContext] item] pullDownNotification];
}
%new
-(BOOL)didAddButton {
for (UIView *object in [self subviews]) {
if (object.tag == 1337) {
return TRUE;
}
}
return FALSE;
}
-(void)layoutSubviews {
if ([[self hermesBulletin] isHermesBulletin] && ![self didAddButton]) {
replyButton = [UIButton buttonWithType:UIButtonTypeCustom];
[replyButton setFrame:CGRectMake(0, 0, 100, 40)];
replyButton.tag = 1337;
replyButton.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
[replyButton setCenter:CGPointMake(self.center.x+((self.frame.size.width/2)-40),self.center.y)];
[replyButton setTitle:@"Reply" forState:UIControlStateNormal];
UIColor* butColor = [UIColor colorWithRed:0/255.0f green:160/255.0f blue:255/255.0f alpha:1.0f];
[replyButton setTitleColor:butColor forState:UIControlStateNormal];
if (appFrom == 1) [replyButton addTarget:self action:@selector(messageReply) forControlEvents:UIControlEventTouchUpInside];
else if (appFrom == 2) [replyButton addTarget:self action:@selector(kikReply) forControlEvents:UIControlEventTouchUpInside];
else [replyButton addTarget:self action:@selector(whatsReply) forControlEvents:UIControlEventTouchUpInside];
NSLog(@"[Hermes3] appFrom is %i", appFrom);
if (shouldShowReply(appFrom)) [self addSubview:replyButton];
}
%orig;
}
%new
-(void)messageReply {
dl(@"[Hermes3] Replying to Messages after touching reply button...");
notify_post("com.phillipt.hermes.responding");
notify_post("com.phillipt.hermes.received");
}
%new
-(void)kikReply {
dl(@"[Hermes3] Replying to Kik after touching reply button...");
notify_post("com.phillipt.hermes.kikReceived");
}
%new
-(void)whatsReply {
dl(@"[Hermes3] Replying to WhatsApp after touching reply button...");
notify_post("com.phillipt.hermes.whatsAppReceived");
}
%end
%ctor {
system("open /Applications/MobileSMS.app");
[[UIApplication sharedApplication] launchApplicationWithIdentifier:@"com.apple.MobileSMS" suspended:YES];
[[UIApplication sharedApplication] launchApplicationWithIdentifier:@"com.kik.chat" suspended:YES];
[[UIApplication sharedApplication] launchApplicationWithIdentifier:@"net.whatsapp.WhatsApp" suspended:YES];
//Yes, I totally understand the irony of having a piracy check in an open source tweak. B) deal with it
if (![[NSFileManager defaultManager] fileExistsAtPath:@"/var/lib/dpkg/info/org.thebigboss.hermes.list"] && ![[NSFileManager defaultManager] fileExistsAtPath:@"/var/lib/dpkg/info/com.phillipt.hermes.list"]) {
pirated = YES;
}
}