1 /* 2 * Copyright 2007-2009 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * François Revol, revol@free.fr 7 * Jonas Sundström, jonas@kirilla.com 8 */ 9 10 /* 11 * CheckItOut: wraps URL mime types around command line apps 12 * or other apps that don't handle them directly. 13 */ 14 #define DEBUG 1 15 16 #include <ctype.h> 17 #include <stdio.h> 18 #include <unistd.h> 19 20 #include <Alert.h> 21 #include <Debug.h> 22 #include <FilePanel.h> 23 #include <NodeInfo.h> 24 #include <Path.h> 25 #include <Roster.h> 26 #include <String.h> 27 #include <Url.h> 28 29 #include "checkitout.h" 30 31 32 const char* kAppSig = "application/x-vnd.Haiku-checkitout"; 33 const char* kTrackerSig = "application/x-vnd.Be-TRAK"; 34 #if __HAIKU__ 35 const char* kTerminalSig = "application/x-vnd.Haiku-Terminal"; 36 #else 37 const char* kTerminalSig = "application/x-vnd.Be-SHEL"; 38 #endif 39 40 CheckItOut::CheckItOut() : BApplication(kAppSig) 41 { 42 } 43 44 45 CheckItOut::~CheckItOut() 46 { 47 } 48 49 50 status_t 51 CheckItOut::_Warn(const char* url) 52 { 53 BString message("An application has requested the system to open the " 54 "following url: \n"); 55 message << "\n" << url << "\n\n"; 56 message << "This type of URL has a potential security risk.\n"; 57 message << "Proceed anyway?"; 58 BAlert* alert = new BAlert("Warning", message.String(), "Proceed", "Stop", NULL, 59 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 60 int32 button; 61 button = alert->Go(); 62 if (button == 0) 63 return B_OK; 64 65 return B_ERROR; 66 } 67 68 69 status_t 70 CheckItOut::_FilePanel(uint32 nodeFlavors, BString &name) 71 { 72 BFilePanel *panel = new BFilePanel(B_SAVE_PANEL); 73 /* 74 BMessenger* target = NULL, const entry_ref* directory = NULL, 75 uint32 nodeFlavors = 0, bool allowMultipleSelection = true, 76 BMessage* message = NULL, BRefFilter* refFilter = NULL, 77 bool modal = false, bool hideWhenDone = true); 78 */ 79 panel->Window()->SetTitle("Check It Out to..."); 80 panel->SetSaveText(name.String()); 81 panel->Show(); 82 return B_OK; 83 } 84 85 86 void 87 CheckItOut::RefsReceived(BMessage* msg) 88 { 89 } 90 91 92 void 93 CheckItOut::MessageReceived(BMessage* msg) 94 { 95 msg->PrintToStream(); 96 switch (msg->what) { 97 case B_SAVE_REQUESTED: 98 { 99 entry_ref ref; 100 BString name; 101 msg->FindRef("directory", &ref); 102 msg->FindString("name", &name); 103 _DoCheckItOut(&ref, name.String()); 104 break; 105 } 106 case B_CANCEL: 107 Quit(); 108 break; 109 } 110 } 111 112 113 void 114 CheckItOut::ArgvReceived(int32 argc, char** argv) 115 { 116 if (argc <= 1) { 117 exit(1); 118 return; 119 } 120 121 BPrivate::Support::BUrl url(argv[1]); 122 fUrlString = url; 123 124 BString full = url.Full(); 125 BString proto = url.Proto(); 126 BString host = url.Host(); 127 BString port = url.Port(); 128 BString user = url.User(); 129 BString pass = url.Pass(); 130 BString path = url.Path(); 131 132 if (url.InitCheck() < 0) { 133 fprintf(stderr, "malformed url: '%s'\n", url.String()); 134 return; 135 } 136 137 // XXX: debug 138 PRINT(("PROTO='%s'\n", proto.String())); 139 PRINT(("HOST='%s'\n", host.String())); 140 PRINT(("PORT='%s'\n", port.String())); 141 PRINT(("USER='%s'\n", user.String())); 142 PRINT(("PASS='%s'\n", pass.String())); 143 PRINT(("PATH='%s'\n", path.String())); 144 145 BString leaf(url.Path()); 146 if (leaf.FindLast('/') > -1) 147 leaf.Remove(0, leaf.FindLast('/') + 1); 148 PRINT(("leaf %s\n", leaf.String())); 149 _FilePanel(B_DIRECTORY_NODE, leaf); 150 151 } 152 153 status_t 154 CheckItOut::_DoCheckItOut(entry_ref *ref, const char *name) 155 { 156 const char* failc = " || read -p 'Press any key'"; 157 const char* pausec = " ; read -p 'Press any key'"; 158 char* args[] = { (char *)"/bin/sh", (char *)"-c", NULL, NULL}; 159 160 BPrivate::Support::BUrl url(fUrlString.String()); 161 BString full = url.Full(); 162 BString proto = url.Proto(); 163 BString host = url.Host(); 164 BString port = url.Port(); 165 BString user = url.User(); 166 BString pass = url.Pass(); 167 BString path = url.Path(); 168 PRINT(("url %s\n", url.String())); 169 BPath refPath(ref); 170 171 if (proto == "git") { 172 BString cmd("git clone "); 173 cmd << url; 174 cmd << " '" << refPath.Path() << "/" << name << "'"; 175 PRINT(("CMD='%s'\n", cmd.String())); 176 cmd << " && open '" << refPath.Path() << "/" << name << "'"; 177 cmd << failc; 178 PRINT(("CMD='%s'\n", cmd.String())); 179 args[2] = (char*)cmd.String(); 180 be_roster->Launch(kTerminalSig, 3, args); 181 return B_OK; 182 } 183 if (proto == "rsync") { 184 BString cmd("rsync "); 185 cmd << url; 186 cmd << " '" << refPath.Path() << "/" << name << "'"; 187 PRINT(("CMD='%s'\n", cmd.String())); 188 cmd << " && open '" << refPath.Path() << "/" << name << "'"; 189 cmd << failc; 190 PRINT(("CMD='%s'\n", cmd.String())); 191 args[2] = (char*)cmd.String(); 192 be_roster->Launch(kTerminalSig, 3, args); 193 return B_OK; 194 } 195 if (proto == "svn" || proto == "svn+ssh") { 196 BString cmd("svn checkout "); 197 cmd << url; 198 cmd << " '" << refPath.Path() << "/" << name << "'"; 199 PRINT(("CMD='%s'\n", cmd.String())); 200 cmd << " && open '" << refPath.Path() << "/" << name << "'"; 201 cmd << failc; 202 PRINT(("CMD='%s'\n", cmd.String())); 203 args[2] = (char*)cmd.String(); 204 be_roster->Launch(kTerminalSig, 3, args); 205 return B_OK; 206 } 207 return B_ERROR; 208 } 209 210 211 status_t 212 CheckItOut::_DecodeUrlString(BString& string) 213 { 214 // TODO: check for %00 and bail out! 215 int32 length = string.Length(); 216 int i; 217 for (i = 0; string[i] && i < length - 2; i++) { 218 if (string[i] == '%' && isxdigit(string[i+1]) 219 && isxdigit(string[i+2])) { 220 int c; 221 sscanf(string.String() + i + 1, "%02x", &c); 222 string.Remove(i, 3); 223 string.Insert((char)c, 1, i); 224 length -= 2; 225 } 226 } 227 228 return B_OK; 229 } 230 231 232 void 233 CheckItOut::ReadyToRun(void) 234 { 235 //Quit(); 236 } 237 238 239 // #pragma mark 240 241 242 int main(int argc, char** argv) 243 { 244 CheckItOut app; 245 if (be_app) 246 app.Run(); 247 return 0; 248 } 249 250