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 SCM URL mime types around command line apps 12 * to check out sources in a user-friendly fashion. 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 alert->SetShortcut(1, B_ESCAPE); 61 int32 button; 62 button = alert->Go(); 63 if (button == 0) 64 return B_OK; 65 66 return B_ERROR; 67 } 68 69 70 status_t 71 CheckItOut::_FilePanel(uint32 nodeFlavors, BString &name) 72 { 73 BFilePanel *panel = new BFilePanel(B_SAVE_PANEL); 74 /* 75 BMessenger* target = NULL, const entry_ref* directory = NULL, 76 uint32 nodeFlavors = 0, bool allowMultipleSelection = true, 77 BMessage* message = NULL, BRefFilter* refFilter = NULL, 78 bool modal = false, bool hideWhenDone = true); 79 */ 80 panel->Window()->SetTitle("Check It Out to..."); 81 panel->SetSaveText(name.String()); 82 panel->Show(); 83 return B_OK; 84 } 85 86 87 void 88 CheckItOut::RefsReceived(BMessage* msg) 89 { 90 } 91 92 93 void 94 CheckItOut::MessageReceived(BMessage* msg) 95 { 96 msg->PrintToStream(); 97 switch (msg->what) { 98 case B_SAVE_REQUESTED: 99 { 100 entry_ref ref; 101 BString name; 102 msg->FindRef("directory", &ref); 103 msg->FindString("name", &name); 104 _DoCheckItOut(&ref, name.String()); 105 break; 106 } 107 case B_CANCEL: 108 Quit(); 109 break; 110 } 111 } 112 113 114 void 115 CheckItOut::ArgvReceived(int32 argc, char** argv) 116 { 117 if (argc <= 1) { 118 exit(1); 119 return; 120 } 121 122 BUrl url(argv[1]); 123 fUrlString = url; 124 125 BString full = BUrl(url).SetProtocol(BString()).UrlString(); 126 BString proto = url.Protocol(); 127 BString host = url.Host(); 128 BString port = BString() << url.Port(); 129 BString user = url.UserInfo(); 130 BString pass = url.Password(); 131 BString path = url.Path(); 132 133 if (!url.IsValid()) { 134 fprintf(stderr, "malformed url: '%s'\n", url.UrlString().String()); 135 return; 136 } 137 138 // XXX: debug 139 PRINT(("PROTO='%s'\n", proto.String())); 140 PRINT(("HOST='%s'\n", host.String())); 141 PRINT(("PORT='%s'\n", port.String())); 142 PRINT(("USER='%s'\n", user.String())); 143 PRINT(("PASS='%s'\n", pass.String())); 144 PRINT(("PATH='%s'\n", path.String())); 145 146 BString leaf(url.Path()); 147 if (leaf.FindLast('/') > -1) 148 leaf.Remove(0, leaf.FindLast('/') + 1); 149 PRINT(("leaf %s\n", leaf.String())); 150 _FilePanel(B_DIRECTORY_NODE, leaf); 151 152 } 153 154 status_t 155 CheckItOut::_DoCheckItOut(entry_ref *ref, const char *name) 156 { 157 const char* failc = " || read -p 'Press any key'"; 158 const char* pausec = " ; read -p 'Press any key'"; 159 char* args[] = { (char *)"/bin/sh", (char *)"-c", NULL, NULL}; 160 161 BUrl url(fUrlString); 162 BString full = BUrl(url).SetProtocol(BString()).UrlString(); 163 BString proto = url.Protocol(); 164 BString host = url.Host(); 165 BString port = BString() << url.Port(); 166 BString user = url.UserInfo(); 167 BString pass = url.Password(); 168 BString path = url.Path(); 169 PRINT(("url %s\n", url.UrlString().String())); 170 BPath refPath(ref); 171 172 if (proto == "git") { 173 BString cmd("git clone "); 174 cmd << url; 175 cmd << " '" << refPath.Path() << "/" << name << "'"; 176 PRINT(("CMD='%s'\n", cmd.String())); 177 cmd << " && open '" << refPath.Path() << "/" << name << "'"; 178 cmd << failc; 179 PRINT(("CMD='%s'\n", cmd.String())); 180 args[2] = (char*)cmd.String(); 181 be_roster->Launch(kTerminalSig, 3, args); 182 return B_OK; 183 } 184 if (proto == "rsync") { 185 BString cmd("rsync "); 186 cmd << url; 187 cmd << " '" << refPath.Path() << "/" << name << "'"; 188 PRINT(("CMD='%s'\n", cmd.String())); 189 cmd << " && open '" << refPath.Path() << "/" << name << "'"; 190 cmd << failc; 191 PRINT(("CMD='%s'\n", cmd.String())); 192 args[2] = (char*)cmd.String(); 193 be_roster->Launch(kTerminalSig, 3, args); 194 return B_OK; 195 } 196 if (proto == "svn" || proto == "svn+ssh") { 197 BString cmd("svn checkout "); 198 cmd << url; 199 cmd << " '" << refPath.Path() << "/" << name << "'"; 200 PRINT(("CMD='%s'\n", cmd.String())); 201 cmd << " && open '" << refPath.Path() << "/" << name << "'"; 202 cmd << failc; 203 PRINT(("CMD='%s'\n", cmd.String())); 204 args[2] = (char*)cmd.String(); 205 be_roster->Launch(kTerminalSig, 3, args); 206 return B_OK; 207 } 208 return B_ERROR; 209 } 210 211 212 status_t 213 CheckItOut::_DecodeUrlString(BString& string) 214 { 215 // TODO: check for %00 and bail out! 216 int32 length = string.Length(); 217 int i; 218 for (i = 0; string[i] && i < length - 2; i++) { 219 if (string[i] == '%' && isxdigit(string[i+1]) 220 && isxdigit(string[i+2])) { 221 int c; 222 sscanf(string.String() + i + 1, "%02x", &c); 223 string.Remove(i, 3); 224 string.Insert((char)c, 1, i); 225 length -= 2; 226 } 227 } 228 229 return B_OK; 230 } 231 232 233 void 234 CheckItOut::ReadyToRun(void) 235 { 236 //Quit(); 237 } 238 239 240 // #pragma mark 241 242 243 int main(int argc, char** argv) 244 { 245 CheckItOut app; 246 if (be_app) 247 app.Run(); 248 return 0; 249 } 250 251