[ Index ] |
PHP Cross Reference of Eventum |
[Summary view] [Print] [Text view]
1 <?php 2 /* vim: set expandtab tabstop=4 shiftwidth=4 encoding=utf-8: */ 3 // +----------------------------------------------------------------------+ 4 // | Eventum - Issue Tracking System | 5 // +----------------------------------------------------------------------+ 6 // | Copyright (c) 2003, 2004, 2005, 2006, 2007 MySQL AB | 7 // | | 8 // | This program is free software; you can redistribute it and/or modify | 9 // | it under the terms of the GNU General Public License as published by | 10 // | the Free Software Foundation; either version 2 of the License, or | 11 // | (at your option) any later version. | 12 // | | 13 // | This program is distributed in the hope that it will be useful, | 14 // | but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 // | GNU General Public License for more details. | 17 // | | 18 // | You should have received a copy of the GNU General Public License | 19 // | along with this program; if not, write to: | 20 // | | 21 // | Free Software Foundation, Inc. | 22 // | 59 Temple Place - Suite 330 | 23 // | Boston, MA 02111-1307, USA. | 24 // +----------------------------------------------------------------------+ 25 // | Authors: João Prado Maia <jpm@mysql.com> | 26 // +----------------------------------------------------------------------+ 27 // 28 // @(#) $Id: xmlrpc.php 3425 2007-11-09 21:11:50Z glen $ 29 // 30 require_once(dirname(__FILE__) . "/../init.php"); 31 require_once (APP_INC_PATH . "db_access.php"); 32 require_once (APP_INC_PATH . "class.auth.php"); 33 require_once (APP_INC_PATH . "class.issue.php"); 34 require_once (APP_INC_PATH . "class.note.php"); 35 require_once (APP_INC_PATH . "class.draft.php"); 36 require_once (APP_INC_PATH . "class.misc.php"); 37 require_once (APP_INC_PATH . "class.project.php"); 38 require_once (APP_INC_PATH . "class.status.php"); 39 require_once (APP_INC_PATH . "class.authorized_replier.php"); 40 require_once (APP_INC_PATH . "class.report.php"); 41 require_once (APP_INC_PATH . "class.template.php"); 42 require_once (APP_INC_PATH . "class.customer.php"); 43 error_reporting(0); 44 require_once(APP_PEAR_PATH . "XML/RPC/Server.php"); 45 46 function authenticate($email, $password) 47 { 48 // XXX: THe role check shouldn't be hardcoded for project 1 49 if ((!Auth::isCorrectPassword($email, $password)) || (User::getRoleByUser(User::getUserIDByEmail($email), 1) <= User::getRoleID("Customer"))) { 50 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Authentication failed for $email.\nYour email/password is invalid or you do not have the proper role"); 51 } else { 52 createFakeCookie($email); 53 return true; 54 } 55 } 56 57 58 $getDeveloperList_sig = array(array($XML_RPC_Struct, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int)); 59 function getDeveloperList($p) 60 { 61 $email = XML_RPC_decode($p->getParam(0)); 62 $password = XML_RPC_decode($p->getParam(1)); 63 $auth = authenticate($email, $password); 64 if (is_object($auth)) { 65 return $auth; 66 } 67 $prj_id = XML_RPC_decode($p->getParam(2)); 68 69 $res = Project::getRemoteAssocList(); 70 if (empty($res)) { 71 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "There are currently no projects setup for remote invocation"); 72 } 73 // check if this project allows remote invocation 74 if (!in_array($prj_id, array_keys($res))) { 75 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "This project does not allow remote invocation"); 76 } 77 78 $res = Project::getAddressBookAssocList($prj_id); 79 if (empty($res)) { 80 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "There are currently no users associated with the given project"); 81 } else { 82 return new XML_RPC_Response(XML_RPC_Encode($res)); 83 } 84 } 85 86 $getSimpleIssueDetails_sig = array(array($XML_RPC_Struct, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int)); 87 function getSimpleIssueDetails($p) 88 { 89 $email = XML_RPC_decode($p->getParam(0)); 90 $password = XML_RPC_decode($p->getParam(1)); 91 $auth = authenticate($email, $password); 92 if (is_object($auth)) { 93 return $auth; 94 } 95 $issue_id = XML_RPC_decode($p->getParam(2)); 96 createFakeCookie($email, Issue::getProjectID($issue_id)); 97 98 $details = Issue::getDetails($issue_id); 99 if (empty($details)) { 100 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Issue #$issue_id could not be found"); 101 } 102 return new XML_RPC_Response(new XML_RPC_Value(array( 103 "summary" => new XML_RPC_Value($details['iss_summary']), 104 "customer" => new XML_RPC_Value(@$details['customer_info']['customer_name']), 105 "status" => new XML_RPC_Value(@$details['sta_title']), 106 "assignments" => new XML_RPC_Value(@$details["assignments"]), 107 "authorized_names" => new XML_RPC_Value(@implode(', ', $details['authorized_names'])) 108 ), "struct")); 109 } 110 111 $getOpenIssues_sig = array(array($XML_RPC_Array, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Boolean, $XML_RPC_String)); 112 function getOpenIssues($p) 113 { 114 $email = XML_RPC_decode($p->getParam(0)); 115 $password = XML_RPC_decode($p->getParam(1)); 116 $auth = authenticate($email, $password); 117 if (is_object($auth)) { 118 return $auth; 119 } 120 $prj_id = XML_RPC_decode($p->getParam(2)); 121 $show_all_issues = XML_RPC_decode($p->getParam(3)); 122 $status = XML_RPC_decode($p->getParam(4)); 123 $status_id = Status::getStatusID($status); 124 $usr_id = User::getUserIDByEmail($email); 125 126 $res = Issue::getOpenIssues($prj_id, $usr_id, $show_all_issues, $status_id); 127 128 if (empty($res)) { 129 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "There are currently no open issues"); 130 } else { 131 $structs = array(); 132 for ($i = 0; $i < count($res); $i++) { 133 $structs[] = new XML_RPC_Value(array( 134 "issue_id" => new XML_RPC_Value($res[$i]['iss_id'], "int"), 135 "summary" => new XML_RPC_Value($res[$i]['iss_summary']), 136 'assigned_users' => new XML_RPC_Value($res[$i]['assigned_users']), 137 'status' => new XML_RPC_Value($res[$i]['sta_title']) 138 ), "struct"); 139 } 140 return new XML_RPC_Response(new XML_RPC_Value($structs, "array")); 141 } 142 } 143 144 $isValidLogin_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String)); 145 function isValidLogin($p) 146 { 147 $email = XML_RPC_decode($p->getParam(0)); 148 $password = XML_RPC_decode($p->getParam(1)); 149 150 if (!Auth::isCorrectPassword($email, $password)) { 151 $is_valid = 'no'; 152 } else { 153 $is_valid = 'yes'; 154 } 155 156 return new XML_RPC_Response(new XML_RPC_Value($is_valid, $XML_RPC_String)); 157 } 158 159 $getUserAssignedProjects_sig = array(array($XML_RPC_Array, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Boolean)); 160 function getUserAssignedProjects($p) 161 { 162 $email = XML_RPC_decode($p->getParam(0)); 163 $password = XML_RPC_decode($p->getParam(1)); 164 $auth = authenticate($email, $password); 165 if (is_object($auth)) { 166 return $auth; 167 } 168 $only_customer_projects = XML_RPC_decode($p->getParam(2)); 169 170 $usr_id = User::getUserIDByEmail($email); 171 $res = Project::getRemoteAssocListByUser($usr_id, $only_customer_projects); 172 if (empty($res)) { 173 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "You are not assigned to any projects at this moment"); 174 } else { 175 $structs = array(); 176 foreach ($res as $prj_id => $prj_title) { 177 $structs[] = new XML_RPC_Value(array( 178 "id" => new XML_RPC_Value($prj_id, "int"), 179 "title" => new XML_RPC_Value($prj_title) 180 ), "struct"); 181 } 182 return new XML_RPC_Response(new XML_RPC_Value($structs, "array")); 183 } 184 } 185 186 $getIssueDetails_sig = array(array($XML_RPC_Struct, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int)); 187 function getIssueDetails($p) 188 { 189 $email = XML_RPC_decode($p->getParam(0)); 190 $password = XML_RPC_decode($p->getParam(1)); 191 $auth = authenticate($email, $password); 192 if (is_object($auth)) { 193 return $auth; 194 } 195 $issue_id = XML_RPC_decode($p->getParam(2)); 196 createFakeCookie($email, Issue::getProjectID($issue_id)); 197 198 $res = Issue::getDetails($issue_id); 199 foreach ($res as $k => $v) { 200 $res[$k] = base64_encode($v); 201 } 202 if (empty($res)) { 203 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Issue #$issue_id could not be found"); 204 } else { 205 // remove some naughty fields 206 unset($res['iss_original_description']); 207 return new XML_RPC_Response(XML_RPC_Encode($res)); 208 } 209 } 210 211 $getTimeTrackingCategories_sig = array(array($XML_RPC_Struct, $XML_RPC_String, $XML_RPC_String)); 212 function getTimeTrackingCategories($p) 213 { 214 $email = XML_RPC_decode($p->getParam(0)); 215 $password = XML_RPC_decode($p->getParam(1)); 216 $auth = authenticate($email, $password); 217 if (is_object($auth)) { 218 return $auth; 219 } 220 $res = Time_Tracking::getAssocCategories(); 221 if (empty($res)) { 222 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "No time tracking categories could be found"); 223 } else { 224 return new XML_RPC_Response(XML_RPC_Encode($res)); 225 } 226 } 227 228 $recordTimeWorked_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Int, $XML_RPC_String, $XML_RPC_Int)); 229 function recordTimeWorked($p) 230 { 231 $email = XML_RPC_decode($p->getParam(0)); 232 $password = XML_RPC_decode($p->getParam(1)); 233 $auth = authenticate($email, $password); 234 if (is_object($auth)) { 235 return $auth; 236 } 237 $issue_id = XML_RPC_decode($p->getParam(2)); 238 $cat_id = XML_RPC_decode($p->getParam(3)); 239 $summary = XML_RPC_decode($p->getParam(4)); 240 $time_spent = XML_RPC_decode($p->getParam(5)); 241 242 $usr_id = User::getUserIDByEmail($email); 243 $res = Time_Tracking::recordRemoteEntry($issue_id, $usr_id, $cat_id, $summary, $time_spent); 244 if ($res == -1) { 245 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Could not record the time tracking entry"); 246 } else { 247 return new XML_RPC_Response(XML_RPC_Encode('OK')); 248 } 249 } 250 251 $setIssueStatus_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_String)); 252 function setIssueStatus($p) 253 { 254 $email = XML_RPC_decode($p->getParam(0)); 255 $password = XML_RPC_decode($p->getParam(1)); 256 $auth = authenticate($email, $password); 257 if (is_object($auth)) { 258 return $auth; 259 } 260 $issue_id = XML_RPC_decode($p->getParam(2)); 261 $new_status = XML_RPC_decode($p->getParam(3)); 262 263 $usr_id = User::getUserIDByEmail($email); 264 $res = Issue::setRemoteStatus($issue_id, $usr_id, $new_status); 265 if ($res == -1) { 266 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Could not set the status to issue #$issue_id"); 267 } else { 268 return new XML_RPC_Response(XML_RPC_Encode('OK')); 269 } 270 } 271 272 $assignIssue_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Int, $XML_RPC_String)); 273 function assignIssue($p) 274 { 275 $email = XML_RPC_decode($p->getParam(0)); 276 $password = XML_RPC_decode($p->getParam(1)); 277 $auth = authenticate($email, $password); 278 if (is_object($auth)) { 279 return $auth; 280 } 281 $issue_id = XML_RPC_decode($p->getParam(2)); 282 $project_id = XML_RPC_decode($p->getParam(3)); 283 $developer = XML_RPC_decode($p->getParam(4)); 284 285 createFakeCookie($email, Issue::getProjectID($issue_id)); 286 287 $usr_id = User::getUserIDByEmail($email); 288 $assignee = User::getUserIDByEmail($developer); 289 if (empty($assignee)) { 290 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Could not find a user with email '$developer'"); 291 } 292 // check if the assignee is even allowed to be in the given project 293 $projects = Project::getRemoteAssocListByUser($assignee); 294 if (!in_array($project_id, array_keys($projects))) { 295 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "The selected developer is not permitted in the project associated with issue #$issue_id"); 296 } 297 298 $res = Issue::remoteAssign($issue_id, $usr_id, $assignee); 299 if ($res == -1) { 300 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Could not assign issue #$issue_id to $developer"); 301 } else { 302 return new XML_RPC_Response(XML_RPC_Encode('OK')); 303 } 304 } 305 306 $takeIssue_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Int)); 307 function takeIssue($p) 308 { 309 $email = XML_RPC_decode($p->getParam(0)); 310 $password = XML_RPC_decode($p->getParam(1)); 311 $auth = authenticate($email, $password); 312 if (is_object($auth)) { 313 return $auth; 314 } 315 $issue_id = XML_RPC_decode($p->getParam(2)); 316 $project_id = XML_RPC_decode($p->getParam(3)); 317 318 createFakeCookie($email, Issue::getProjectID($issue_id)); 319 320 // check if issue currently is un-assigned 321 $current_assignees = Issue::getAssignedUsers($issue_id); 322 if (count($current_assignees) > 0) { 323 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Issue is currently assigned to " . join(',', $current_assignees)); 324 } 325 326 $usr_id = User::getUserIDByEmail($email); 327 328 // check if the assignee is even allowed to be in the given project 329 $projects = Project::getRemoteAssocListByUser($usr_id); 330 if (!in_array($project_id, array_keys($projects))) { 331 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "The selected developer is not permitted in the project associated with issue #$issue_id"); 332 } 333 334 $res = Issue::remoteAssign($issue_id, $usr_id, $usr_id); 335 if ($res == -1) { 336 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Could not assign issue #$issue_id to $email"); 337 } else { 338 $res = Issue::setRemoteStatus($issue_id, $usr_id, "Assigned"); 339 if ($res == -1) { 340 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Could not set status for issue #$issue_id"); 341 } 342 return new XML_RPC_Response(XML_RPC_Encode('OK')); 343 } 344 } 345 346 $addAuthorizedReplier_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Int, $XML_RPC_String)); 347 function addAuthorizedReplier($p) 348 { 349 $email = XML_RPC_decode($p->getParam(0)); 350 $password = XML_RPC_decode($p->getParam(1)); 351 $auth = authenticate($email, $password); 352 if (is_object($auth)) { 353 return $auth; 354 } 355 $issue_id = XML_RPC_decode($p->getParam(2)); 356 $project_id = XML_RPC_decode($p->getParam(3)); 357 $new_replier = XML_RPC_decode($p->getParam(4)); 358 359 $usr_id = User::getUserIDByEmail($email); 360 $replier_usr_id = User::getUserIDByEmail($new_replier); 361 362 // if this is an actual user, not just an email address check permissions 363 if (!empty($replier_usr_id)) { 364 // check if the assignee is even allowed to be in the given project 365 $projects = Project::getRemoteAssocListByUser($replier_usr_id); 366 if (!in_array($project_id, array_keys($projects))) { 367 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "The given user is not permitted in the project associated with issue #$issue_id"); 368 } 369 } 370 371 // check if user is already authorized 372 if (Authorized_Replier::isAuthorizedReplier($issue_id, $new_replier)) { 373 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "The given user is already an authorized replier on issue #$issue_id"); 374 } 375 376 $res = Authorized_Replier::remoteAddAuthorizedReplier($issue_id, $usr_id, $new_replier); 377 if ($res == -1) { 378 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Could not add '$new_replier' as an authorized replier to issue #$issue_id"); 379 } else { 380 return new XML_RPC_Response(XML_RPC_Encode('OK')); 381 } 382 } 383 384 $getFileList_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int)); 385 function getFileList($p) 386 { 387 $email = XML_RPC_decode($p->getParam(0)); 388 $password = XML_RPC_decode($p->getParam(1)); 389 $auth = authenticate($email, $password); 390 if (is_object($auth)) { 391 return $auth; 392 } 393 $issue_id = XML_RPC_decode($p->getParam(2)); 394 createFakeCookie($email, Issue::getProjectID($issue_id)); 395 396 $res = Attachment::getList($issue_id); 397 if (empty($res)) { 398 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "No files could be found"); 399 } else { 400 return new XML_RPC_Response(XML_RPC_Encode($res)); 401 } 402 } 403 404 $getFile_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int)); 405 function getFile($p) 406 { 407 $email = XML_RPC_decode($p->getParam(0)); 408 $password = XML_RPC_decode($p->getParam(1)); 409 $auth = authenticate($email, $password); 410 if (is_object($auth)) { 411 return $auth; 412 } 413 $file_id = XML_RPC_decode($p->getParam(2)); 414 415 $res = Attachment::getDetails($file_id); 416 if (empty($res)) { 417 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "The requested file could not be found"); 418 } else { 419 $res['iaf_file'] = base64_encode($res['iaf_file']); 420 return new XML_RPC_Response(XML_RPC_Encode($res)); 421 } 422 } 423 424 $lookupCustomer_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_String, $XML_RPC_String)); 425 function lookupCustomer($p) 426 { 427 $email = XML_RPC_decode($p->getParam(0)); 428 $password = XML_RPC_decode($p->getParam(1)); 429 $auth = authenticate($email, $password); 430 if (is_object($auth)) { 431 return $auth; 432 } 433 $prj_id = XML_RPC_decode($p->getParam(2)); 434 $field = XML_RPC_decode($p->getParam(3)); 435 $value = XML_RPC_decode($p->getParam(4)); 436 437 $possible_fields = array('email', 'support', 'customer'); 438 if (!in_array($field, $possible_fields)) { 439 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Unknown field type '$field'"); 440 } 441 442 $usr_id = User::getUserIDByEmail($email); 443 // only customers should be able to use this page 444 $role_id = User::getRoleByUser($usr_id, $prj_id); 445 if ($role_id < User::getRoleID('Developer')) { 446 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "You don't have the appropriate permissions to lookup customer information"); 447 } else { 448 $res = Customer::lookup($prj_id, $field, $value); 449 return new XML_RPC_Response(XML_RPC_Encode($res)); 450 } 451 } 452 453 $closeIssue_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Boolean, $XML_RPC_String)); 454 function closeIssue($p) 455 { 456 $email = XML_RPC_decode($p->getParam(0)); 457 $password = XML_RPC_decode($p->getParam(1)); 458 $auth = authenticate($email, $password); 459 if (is_object($auth)) { 460 return $auth; 461 } 462 $usr_id = User::getUserIDByEmail($email); 463 $issue_id = XML_RPC_decode($p->getParam(2)); 464 $new_status = XML_RPC_decode($p->getParam(3)); 465 $status_id = Status::getStatusID($new_status); 466 $resolution_id = XML_RPC_decode($p->getParam(4)); 467 $send_notification = XML_RPC_decode($p->getParam(5)); 468 $note = XML_RPC_decode($p->getParam(6)); 469 470 createFakeCookie($email, Issue::getProjectID($issue_id)); 471 472 $res = Issue::close($usr_id, $issue_id, $send_notification, $resolution_id, $status_id, $note); 473 if ($res == -1) { 474 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Could not close issue #$issue_id"); 475 } else { 476 $prj_id = Issue::getProjectID($issue_id); 477 if ((Customer::hasCustomerIntegration($prj_id)) && (Customer::hasPerIncidentContract($prj_id, Issue::getCustomerID($issue_id)))) { 478 return new XML_RPC_Response(XML_RPC_Encode('INCIDENT')); 479 } else { 480 return new XML_RPC_Response(XML_RPC_Encode('OK')); 481 } 482 } 483 } 484 485 $getClosedAbbreviationAssocList_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int)); 486 function getClosedAbbreviationAssocList($p) 487 { 488 $email = XML_RPC_decode($p->getParam(0)); 489 $password = XML_RPC_decode($p->getParam(1)); 490 $auth = authenticate($email, $password); 491 if (is_object($auth)) { 492 return $auth; 493 } 494 $prj_id = XML_RPC_decode($p->getParam(2)); 495 496 $res = Status::getClosedAbbreviationAssocList($prj_id); 497 return new XML_RPC_Response(XML_RPC_Encode($res)); 498 } 499 500 $getAbbreviationAssocList_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Boolean)); 501 function getAbbreviationAssocList($p) 502 { 503 $email = XML_RPC_decode($p->getParam(0)); 504 $password = XML_RPC_decode($p->getParam(1)); 505 $auth = authenticate($email, $password); 506 if (is_object($auth)) { 507 return $auth; 508 } 509 $prj_id = XML_RPC_decode($p->getParam(2)); 510 $show_closed = XML_RPC_decode($p->getParam(3)); 511 512 $res = Status::getAbbreviationAssocList($prj_id, $show_closed); 513 return new XML_RPC_Response(XML_RPC_Encode($res)); 514 } 515 516 $getEmailListing_sig = array(array($XML_RPC_Array, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int)); 517 function getEmailListing($p) 518 { 519 $email = XML_RPC_decode($p->getParam(0)); 520 $password = XML_RPC_decode($p->getParam(1)); 521 $auth = authenticate($email, $password); 522 if (is_object($auth)) { 523 return $auth; 524 } 525 $issue_id = XML_RPC_decode($p->getParam(2)); 526 $emails = Support::getEmailsByIssue($issue_id); 527 528 // since xml-rpc has issues, lets base64 encode everything 529 if (is_array($emails)) { 530 for ($i = 0; $i < count($emails); $i++) { 531 unset($emails[$i]["seb_body"]); 532 foreach ($emails[$i] as $key => $val) { 533 $emails[$i][$key] = base64_encode($val); 534 } 535 } 536 } 537 return new XML_RPC_Response(XML_RPC_Encode($emails)); 538 } 539 540 $getEmail_sig = array(array($XML_RPC_Array, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Int)); 541 function getEmail($p) 542 { 543 $email = XML_RPC_decode($p->getParam(0)); 544 $password = XML_RPC_decode($p->getParam(1)); 545 $auth = authenticate($email, $password); 546 if (is_object($auth)) { 547 return $auth; 548 } 549 $issue_id = XML_RPC_decode($p->getParam(2)); 550 $email_id = XML_RPC_decode($p->getParam(3)); 551 $email = Support::getEmailBySequence($issue_id, $email_id); 552 553 // get requested email 554 if ((count($email) < 1) || (!is_array($email))) { 555 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Email #" . $email_id . " does not exist for issue #$issue_id"); 556 } 557 // since xml-rpc has issues, lets base64 encode everything 558 foreach ($email as $key => $val) { 559 $email[$key] = base64_encode($val); 560 } 561 return new XML_RPC_Response(XML_RPC_Encode($email)); 562 } 563 564 $getNoteListing_sig = array(array($XML_RPC_Array, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int)); 565 function getNoteListing($p) 566 { 567 $email = XML_RPC_decode($p->getParam(0)); 568 $password = XML_RPC_decode($p->getParam(1)); 569 $auth = authenticate($email, $password); 570 if (is_object($auth)) { 571 return $auth; 572 } 573 $issue_id = XML_RPC_decode($p->getParam(2)); 574 createFakeCookie($email, Issue::getProjectID($issue_id)); 575 $notes = Note::getListing($issue_id); 576 577 // since xml-rpc has issues, lets base64 encode everything 578 for ($i = 0; $i < count($notes); $i++) { 579 foreach ($notes[$i] as $key => $val) { 580 $notes[$i][$key] = base64_encode($val); 581 } 582 } 583 return new XML_RPC_Response(XML_RPC_Encode($notes)); 584 } 585 586 $getNote_sig = array(array($XML_RPC_Array, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Int)); 587 function getNote($p) 588 { 589 $email = XML_RPC_decode($p->getParam(0)); 590 $password = XML_RPC_decode($p->getParam(1)); 591 $auth = authenticate($email, $password); 592 if (is_object($auth)) { 593 return $auth; 594 } 595 $issue_id = XML_RPC_decode($p->getParam(2)); 596 $note_id = XML_RPC_decode($p->getParam(3)); 597 $note = Note::getNoteBySequence($issue_id, $note_id); 598 599 if ((count($note) < 1) || (!is_array($note))) { 600 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Note #" . $note_id . " does not exist for issue #$issue_id"); 601 } 602 // since xml-rpc has issues, lets base64 encode everything 603 foreach ($note as $key => $val) { 604 $note[$key] = base64_encode($val); 605 } 606 return new XML_RPC_Response(XML_RPC_Encode($note)); 607 } 608 609 $convertNote_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Int, $XML_RPC_String, $XML_RPC_Boolean)); 610 function convertNote($p) 611 { 612 $email = XML_RPC_decode($p->getParam(0)); 613 $password = XML_RPC_decode($p->getParam(1)); 614 $auth = authenticate($email, $password); 615 if (is_object($auth)) { 616 return $auth; 617 } 618 $issue_id = XML_RPC_decode($p->getParam(2)); 619 $note_id = XML_RPC_decode($p->getParam(3)); 620 $target = XML_RPC_decode($p->getParam(4)); 621 $authorize_sender = XML_RPC_decode($p->getParam(5)); 622 623 createFakeCookie($email, Issue::getProjectID($issue_id)); 624 $res = Note::convertNote($note_id, $target, $authorize_sender); 625 if ($res) { 626 return new XML_RPC_Response(XML_RPC_Encode("OK")); 627 } else { 628 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Error converting note"); 629 } 630 } 631 632 $mayChangeIssue_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int)); 633 function mayChangeIssue($p) 634 { 635 $email = XML_RPC_decode($p->getParam(0)); 636 $password = XML_RPC_decode($p->getParam(1)); 637 $auth = authenticate($email, $password); 638 if (is_object($auth)) { 639 return $auth; 640 } 641 $issue_id = XML_RPC_decode($p->getParam(2)); 642 $usr_id = User::getUserIDByEmail($email); 643 644 $assignees = Issue::getAssignedUserIDs($issue_id); 645 if (count($assignees) > 0) { 646 if (in_array($usr_id, $assignees)) { 647 return new XML_RPC_Response(XML_RPC_Encode("yes")); 648 } else { 649 return new XML_RPC_Response(XML_RPC_Encode("no")); 650 } 651 } else { 652 return new XML_RPC_Response(XML_RPC_Encode("yes")); 653 } 654 } 655 656 $getWeeklyReport_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int)); 657 function getWeeklyReport($p) 658 { 659 $email = XML_RPC_decode($p->getParam(0)); 660 $password = XML_RPC_decode($p->getParam(1)); 661 $auth = authenticate($email, $password); 662 if (is_object($auth)) { 663 return $auth; 664 } 665 $week = abs(XML_RPC_decode($p->getParam(2))); 666 $start = XML_RPC_decode($p->getParam(3)); 667 $end = XML_RPC_decode($p->getParam(4)); 668 $separate_closed = XML_RPC_decode($p->getParam(5)); 669 670 // we have to set a project so the template class works, even though the weekly report doesn't actually need it 671 $projects = Project::getAssocList(Auth::getUserID()); 672 createFakeCookie($email, current(array_keys($projects))); 673 674 // figure out the correct week 675 if ((empty($start)) || (empty($end))) { 676 $start = date("U") - (DAY * (date("w") - 1)); 677 if ($week > 0) { 678 $start = ($start - (WEEK * $week)); 679 } 680 $end = date("Y-m-d", ($start + (DAY * 6))); 681 $start = date("Y-m-d", $start); 682 } 683 684 if ($separate_closed) { 685 // emulate smarty value for reports/weekly_data.tpl.tmpl: 686 // {if $smarty.post.separate_closed == 1} 687 $_POST['separate_closed'] = true; 688 } 689 $tpl = new Template_API(); 690 $tpl->setTemplate("reports/weekly_data.tpl.html"); 691 $tpl->assign("data", Report::getWeeklyReport(User::getUserIDByEmail($email), $start, $end, $separate_closed)); 692 693 $ret = $tpl->getTemplateContents(). "\n"; 694 return new XML_RPC_Response(XML_RPC_Encode(base64_encode($ret))); 695 } 696 697 $getResolutionAssocList_sig = array(array($XML_RPC_String)); 698 function getResolutionAssocList($p) 699 { 700 701 $res = Resolution::getAssocList(); 702 return new XML_RPC_Response(XML_RPC_Encode($res)); 703 } 704 705 $timeClock_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_String)); 706 function timeClock($p) 707 { 708 $email = XML_RPC_decode($p->getParam(0)); 709 $password = XML_RPC_decode($p->getParam(1)); 710 $auth = authenticate($email, $password); 711 if (is_object($auth)) { 712 return $auth; 713 } 714 $action = XML_RPC_decode($p->getParam(2)); 715 716 if ($action == "in") { 717 $res = User::clockIn(User::getUserIDByEmail($email)); 718 } elseif ($action == "out") { 719 $res = User::clockOut(User::getUserIDByEmail($email)); 720 } else { 721 if (User::isClockedIn(User::getUserIDByEmail($email))) { 722 $msg = "is clocked in"; 723 } else { 724 $msg = "is clocked out"; 725 } 726 return new XML_RPC_Response(XML_RPC_Encode("$email " . $msg . ".\n")); 727 } 728 729 if ($res == 1) { 730 return new XML_RPC_Response(XML_RPC_Encode("$email successfully clocked " . $action . ".\n")); 731 } else { 732 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Error clocking " . $action . ".\n"); 733 } 734 } 735 736 737 $getDraftListing_sig = array(array($XML_RPC_Array, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int)); 738 function getDraftListing($p) 739 { 740 $email = XML_RPC_decode($p->getParam(0)); 741 $password = XML_RPC_decode($p->getParam(1)); 742 $auth = authenticate($email, $password); 743 if (is_object($auth)) { 744 return $auth; 745 } 746 $issue_id = XML_RPC_decode($p->getParam(2)); 747 748 $drafts = Draft::getList($issue_id); 749 750 // since xml-rpc has issues, lets base64 encode everything 751 for ($i = 0; $i < count($drafts); $i++) { 752 foreach ($drafts[$i] as $key => $val) { 753 $drafts[$i][$key] = base64_encode($val); 754 } 755 } 756 return new XML_RPC_Response(XML_RPC_Encode($drafts)); 757 } 758 759 $getDraft_sig = array(array($XML_RPC_Array, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Int)); 760 function getDraft($p) 761 { 762 $email = XML_RPC_decode($p->getParam(0)); 763 $password = XML_RPC_decode($p->getParam(1)); 764 $auth = authenticate($email, $password); 765 if (is_object($auth)) { 766 return $auth; 767 } 768 $issue_id = XML_RPC_decode($p->getParam(2)); 769 $draft_id = XML_RPC_decode($p->getParam(3)); 770 $draft = Draft::getDraftBySequence($issue_id, $draft_id); 771 772 if ((count($draft) < 1) || (!is_array($draft))) { 773 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Draft #" . $draft_id . " does not exist for issue #$issue_id"); 774 } 775 if (empty($draft['to'])) { 776 $draft['to'] = "Notification List"; 777 } 778 $draft['cc'] = @join(", ", $draft['cc']); 779 // since xml-rpc has issues, lets base64 encode everything 780 foreach ($draft as $key => $val) { 781 $draft[$key] = base64_encode($val); 782 } 783 return new XML_RPC_Response(XML_RPC_Encode($draft)); 784 } 785 786 $sendDraft_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Int)); 787 function sendDraft($p) 788 { 789 $email = XML_RPC_decode($p->getParam(0)); 790 $password = XML_RPC_decode($p->getParam(1)); 791 $auth = authenticate($email, $password); 792 if (is_object($auth)) { 793 return $auth; 794 } 795 $issue_id = XML_RPC_decode($p->getParam(2)); 796 $draft_id = XML_RPC_decode($p->getParam(3)); 797 $draft = Draft::getDraftBySequence($issue_id, $draft_id); 798 createFakeCookie($email, Issue::getProjectID($issue_id)); 799 800 if ((count($draft) < 1) || (!is_array($draft))) { 801 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Draft #" . $draft_id . " does not exist for issue #$issue_id"); 802 } 803 $res = Draft::send($draft["emd_id"]); 804 if ($res == 1) { 805 return new XML_RPC_Response(XML_RPC_Encode("Draft #" . $draft_id . " sent successfully.\n")); 806 } else { 807 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Error sending Draft #" . $draft_id . "\n"); 808 } 809 } 810 811 $redeemIssue_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Struct)); 812 function redeemIssue($p) 813 { 814 $email = XML_RPC_decode($p->getParam(0)); 815 $password = XML_RPC_decode($p->getParam(1)); 816 $auth = authenticate($email, $password); 817 if (is_object($auth)) { 818 return $auth; 819 } 820 $issue_id = XML_RPC_decode($p->getParam(2)); 821 $types = XML_RPC_decode($p->getParam(3)); 822 823 $prj_id = Issue::getProjectID($issue_id); 824 createFakeCookie($email, $prj_id); 825 $customer_id = Issue::getCustomerID($issue_id); 826 827 $all_types = Customer::getIncidentTypes($prj_id); 828 829 if (!Customer::hasCustomerIntegration($prj_id)) { 830 // no customer integration 831 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "No customer integration for issue #$issue_id"); 832 } elseif (!Customer::hasPerIncidentContract($prj_id, $customer_id)) { 833 // check if is per incident contract 834 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Customer for issue #$issue_id does not have a per-incident contract"); 835 } else { 836 // check if incidents are remaining 837 foreach ($types as $type_id) { 838 if (Customer::isRedeemedIncident($prj_id, $issue_id, $type_id)) { 839 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Issue #$issue_id is already marked as redeemed incident of type " . $all_types[$type_id]); 840 } elseif (!Customer::hasIncidentsLeft($prj_id, $customer_id, $type_id)) { 841 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Customer for issue #$issue_id has no remaining incidents of type " . $all_types[$type_id]); 842 } 843 } 844 } 845 846 foreach ($types as $type_id) { 847 $res = Customer::flagIncident($prj_id, $issue_id, $type_id); 848 if ($res == -1) { 849 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "An error occured trying to mark issue as redeemed."); 850 } 851 } 852 return new XML_RPC_Response(XML_RPC_Encode('OK')); 853 } 854 855 $unredeemIssue_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Struct)); 856 function unredeemIssue($p) 857 { 858 $email = XML_RPC_decode($p->getParam(0)); 859 $password = XML_RPC_decode($p->getParam(1)); 860 $auth = authenticate($email, $password); 861 if (is_object($auth)) { 862 return $auth; 863 } 864 $issue_id = XML_RPC_decode($p->getParam(2)); 865 $types = XML_RPC_decode($p->getParam(3)); 866 867 $prj_id = Issue::getProjectID($issue_id); 868 createFakeCookie($email, $prj_id); 869 870 $customer_id = Issue::getCustomerID($issue_id); 871 872 if (!Customer::hasCustomerIntegration($prj_id)) { 873 // no customer integration 874 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "No customer integration for issue #$issue_id"); 875 } elseif (!Customer::hasPerIncidentContract($prj_id, $customer_id)) { 876 // check if is per incident contract 877 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Customer for issue #$issue_id does not have a per-incident contract"); 878 } else { 879 // check if incidents are remaining 880 foreach ($types as $type_id) { 881 if (!Customer::isRedeemedIncident($prj_id, $issue_id, $type_id)) { 882 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Issue #$issue_id is not marked as redeemed incident of type " . $all_types[$type_id]); 883 } 884 } 885 } 886 887 foreach ($types as $type_id) { 888 $res = Customer::unflagIncident($prj_id, $issue_id, $type_id); 889 if ($res == -1) { 890 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "An error occured trying to mark issue as unredeemed."); 891 } 892 } 893 return new XML_RPC_Response(XML_RPC_Encode('OK')); 894 } 895 896 $getIncidentTypes_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_Int, $XML_RPC_Boolean)); 897 function getIncidentTypes($p) 898 { 899 $email = XML_RPC_decode($p->getParam(0)); 900 $password = XML_RPC_decode($p->getParam(1)); 901 $auth = authenticate($email, $password); 902 if (is_object($auth)) { 903 return $auth; 904 } 905 $issue_id = XML_RPC_decode($p->getParam(2)); 906 $redeemed_only = XML_RPC_decode($p->getParam(3)); 907 908 $prj_id = Issue::getProjectID($issue_id); 909 createFakeCookie($email, $prj_id); 910 $customer_id = Issue::getCustomerID($issue_id); 911 912 if (!Customer::hasCustomerIntegration($prj_id)) { 913 // no customer integration 914 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "No customer integration for issue #$issue_id"); 915 } elseif (!Customer::hasPerIncidentContract($prj_id, $customer_id)) { 916 // check if is per incident contract 917 return new XML_RPC_Response(0, $XML_RPC_erruser+1, "Customer for issue #$issue_id does not have a per-incident contract"); 918 } 919 920 $details = Customer::getDetails($prj_id, $customer_id); 921 922 foreach ($details['incident_details'] as $type_id => $type_details) { 923 $is_redeemed = Customer::isRedeemedIncident($prj_id, $issue_id, $type_id); 924 if ((($redeemed_only) && (!$is_redeemed)) || ((!$redeemed_only) && ($is_redeemed))) { 925 unset($details['incident_details'][$type_id]); 926 } 927 } 928 929 return new XML_RPC_Response(XML_RPC_Encode($details['incident_details'])); 930 } 931 932 $logCommand_sig = array(array($XML_RPC_String, $XML_RPC_String, $XML_RPC_String, $XML_RPC_String)); 933 function logCommand($p) 934 { 935 $email = XML_RPC_decode($p->getParam(0)); 936 $password = XML_RPC_decode($p->getParam(1)); 937 $auth = authenticate($email, $password); 938 if (is_object($auth)) { 939 return $auth; 940 } 941 $command = base64_decode(XML_RPC_decode($p->getParam(2))); 942 943 $msg = $email . "\t" . $command . "\n"; 944 945 $fp = @fopen(APP_CLI_LOG, "a"); 946 @fwrite($fp, $msg); 947 @fclose($fp); 948 949 return new XML_RPC_Response(XML_RPC_Encode('OK')); 950 } 951 952 /** 953 * Fakes the creation of the login cookie 954 */ 955 function createFakeCookie($email, $project = false) 956 { 957 $cookie = array( 958 "email" => $email 959 ); 960 $_COOKIE[APP_COOKIE] = base64_encode(serialize($cookie)); 961 if ($project) { 962 $cookie = array( 963 "prj_id" => $project, 964 "remember" => false 965 ); 966 } 967 $_COOKIE[APP_PROJECT_COOKIE] = base64_encode(serialize($cookie)); 968 } 969 970 971 $services = array( 972 "mayChangeIssue" => array( 973 'function' => 'mayChangeIssue', 974 'signature' => $mayChangeIssue_sig 975 ), 976 "getClosedAbbreviationAssocList" => array( 977 'function' => 'getClosedAbbreviationAssocList', 978 'signature' => $getClosedAbbreviationAssocList_sig 979 ), 980 "getAbbreviationAssocList" => array( 981 'function' => 'getAbbreviationAssocList', 982 'signature' => $getAbbreviationAssocList_sig 983 ), 984 "closeIssue" => array( 985 'function' => 'closeIssue', 986 'signature' => $closeIssue_sig 987 ), 988 "lookupCustomer" => array( 989 'function' => "lookupCustomer", 990 'signature' => $lookupCustomer_sig 991 ), 992 "getFile" => array( 993 'function' => "getFile", 994 'signature' => $getFile_sig 995 ), 996 "getFileList" => array( 997 'function' => "getFileList", 998 'signature' => $getFileList_sig 999 ), 1000 "assignIssue" => array( 1001 'function' => "assignIssue", 1002 'signature' => $assignIssue_sig 1003 ), 1004 "takeIssue" => array( 1005 'function' => "takeIssue", 1006 'signature' => $takeIssue_sig 1007 ), 1008 "addAuthorizedReplier" => array( 1009 'function' => "addAuthorizedReplier", 1010 'signature' => $addAuthorizedReplier_sig 1011 ), 1012 "setIssueStatus" => array( 1013 'function' => "setIssueStatus", 1014 'signature' => $setIssueStatus_sig 1015 ), 1016 "recordTimeWorked" => array( 1017 'function' => "recordTimeWorked", 1018 'signature' => $recordTimeWorked_sig 1019 ), 1020 "getTimeTrackingCategories" => array( 1021 'function' => "getTimeTrackingCategories", 1022 'signature' => $getTimeTrackingCategories_sig 1023 ), 1024 "getIssueDetails" => array( 1025 'function' => "getIssueDetails", 1026 'signature' => $getIssueDetails_sig 1027 ), 1028 "getUserAssignedProjects" => array( 1029 'function' => "getUserAssignedProjects", 1030 'signature' => $getUserAssignedProjects_sig 1031 ), 1032 "isValidLogin" => array( 1033 'function' => "isValidLogin", 1034 'signature' => $isValidLogin_sig 1035 ), 1036 "getOpenIssues" => array( 1037 'function' => "getOpenIssues", 1038 'signature' => $getOpenIssues_sig 1039 ), 1040 "getSimpleIssueDetails" => array( 1041 'function' => "getSimpleIssueDetails", 1042 'signature' => $getSimpleIssueDetails_sig 1043 ), 1044 "getDeveloperList" => array( 1045 "function" => "getDeveloperList", 1046 'signature' => $getDeveloperList_sig 1047 ), 1048 "getEmailListing" => array( 1049 "function" => "getEmailListing", 1050 "signature" => $getEmailListing_sig 1051 ), 1052 "getEmail" => array( 1053 "function" => "getEmail", 1054 "signature" => $getEmail_sig 1055 ), 1056 "getNoteListing" => array( 1057 "function" => "getNoteListing", 1058 "signature" => $getNoteListing_sig 1059 ), 1060 "getNote" => array( 1061 "function" => "getNote", 1062 "signature" => $getNote_sig 1063 ), 1064 "convertNote" => array( 1065 "function" => "convertNote", 1066 "signature" => $convertNote_sig 1067 ), 1068 "getWeeklyReport" => array( 1069 "function" => "getWeeklyReport", 1070 "signature" => $getWeeklyReport_sig 1071 ), 1072 "getResolutionAssocList" => array( 1073 "function" => "getResolutionAssocList", 1074 "signature" => $getResolutionAssocList_sig 1075 ), 1076 "timeClock" => array( 1077 "function" => "timeClock", 1078 "signature" => $timeClock_sig 1079 ), 1080 "getDraftListing" => array( 1081 "function" => "getDraftListing", 1082 "signature" => $getDraftListing_sig 1083 ), 1084 "getDraft" => array( 1085 "function" => "getDraft", 1086 "signature" => $getDraft_sig 1087 ), 1088 "sendDraft" => array( 1089 "function" => "sendDraft", 1090 "signature" => $sendDraft_sig 1091 ), 1092 "redeemIssue" => array( 1093 "function" => "redeemIssue", 1094 "signature" => $redeemIssue_sig 1095 ), 1096 "unredeemIssue" => array( 1097 "function" => "unredeemIssue", 1098 "signature" => $unredeemIssue_sig 1099 ), 1100 "getIncidentTypes" => array( 1101 "function" => "getIncidentTypes", 1102 "signature" => $getIncidentTypes_sig 1103 ), 1104 "logCommand" => array( 1105 "function" => "logCommand", 1106 "signature" => $logCommand_sig 1107 ) 1108 ); 1109 $server = new XML_RPC_Server($services);
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Dec 19 21:21:33 2007 | Cross-referenced by PHPXref 0.7 |