sloodle_setup_user.lslp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. //
  2. // The line above should be left blank to avoid script errors in OpenSim.
  3. // Sloodle user-centric configuration script.
  4. // Allows users (e.g. students) to authorise and configure user-centric objects themselves.
  5. // Part of the Sloodle project (www.sloodle.org)
  6. //
  7. // Copyright (c) 2008 Sloodle
  8. // Released under the GNU GPL
  9. //
  10. // Contributors:
  11. // Peter R. Bloomfield
  12. integer SLOODLE_CHANNEL_ERROR_TRANSLATION_REQUEST=-1828374651; // this channel is used to send status codes for translation to the error_messages lsl script
  13. integer SLOODLE_CHANNEL_OBJECT_DIALOG = -3857343;
  14. string SLOODLE_EOF = "sloodleeof";
  15. integer SLOODLE_CHANNEL_AVATAR_DIALOG = 1001;
  16. string SLOODLE_VERSION_LINKER = "/mod/sloodle/version_linker.php";
  17. string SLOODLE_USER_AUTH_LINKER = "/mod/sloodle/login/user_object_linker.php";
  18. string SLOODLE_USER_AUTH_INTERFACE = "/mod/sloodle/login/user_object_auth.php";
  19. string SLOODLE_AUTH_CHECKER = "/mod/sloodle/login/check_user_auth_linker.php";
  20. float SLOODLE_VERSION_MIN = 0.3; // Minimum required version of Sloodle
  21. key httpcheckmoodle = NULL_KEY;
  22. key httpauthobject = NULL_KEY;
  23. key httpcheckauth = NULL_KEY;
  24. string sloodleserverroot = "";
  25. string sloodlepwd = ""; // stores the object-specific session key (UUID|pwd)
  26. string sloodleauthurl = ""; // URL which will be used to complete the authorisation process
  27. string password = ""; // stores the self-generated part of the password
  28. ///// TRANSLATION /////
  29. // Link message channels
  30. integer SLOODLE_CHANNEL_TRANSLATION_REQUEST = -1928374651;
  31. integer SLOODLE_CHANNEL_TRANSLATION_RESPONSE = -1928374652;
  32. // Translation output methods
  33. string SLOODLE_TRANSLATE_LINK = "link"; // No output parameters - simply returns the translation on SLOODLE_TRANSLATION_RESPONSE link message channel
  34. string SLOODLE_TRANSLATE_SAY = "say"; // 1 output parameter: chat channel number
  35. string SLOODLE_TRANSLATE_WHISPER = "whisper"; // 1 output parameter: chat channel number
  36. string SLOODLE_TRANSLATE_SHOUT = "shout"; // 1 output parameter: chat channel number
  37. string SLOODLE_TRANSLATE_REGION_SAY = "regionsay"; // 1 output parameter: chat channel number
  38. string SLOODLE_TRANSLATE_OWNER_SAY = "ownersay"; // No output parameters
  39. string SLOODLE_TRANSLATE_DIALOG = "dialog"; // Recipient avatar should be identified in link message keyval. At least 2 output parameters: first the channel number for the dialog, and then 1 to 12 button label strings.
  40. string SLOODLE_TRANSLATE_LOAD_URL = "loadurl"; // Recipient avatar should be identified in link message keyval. 1 output parameter, containing the URL.
  41. string SLOODLE_TRANSLATE_HOVER_TEXT = "hovertext"; // 2 output parameters: colour <r,g,b>, and alpha value
  42. string SLOODLE_TRANSLATE_IM = "instantmessage"; // Recipient avatar should be identified in link message keyval. No output parameters.
  43. //functions
  44. /******************************************************************************************************************************
  45. * sloodle_error_code -
  46. * Author: Paul Preibisch
  47. * Description - This function sends a linked message on the SLOODLE_CHANNEL_ERROR_TRANSLATION_REQUEST channel
  48. * The error_messages script hears this, translates the status code and sends an instant message to the avuuid
  49. * Params: method - SLOODLE_TRANSLATE_SAY, SLOODLE_TRANSLATE_IM etc
  50. * Params: avuuid - this is the avatar UUID to that an instant message with the translated error code will be sent to
  51. * Params: status code - the status code of the error as on our wiki: http://slisweb.sjsu.edu/sl/index.php/Sloodle_status_codes
  52. *******************************************************************************************************************************/
  53. sloodle_error_code(string method, key avuuid,integer statuscode){
  54. llMessageLinked(LINK_SET, SLOODLE_CHANNEL_ERROR_TRANSLATION_REQUEST, method+"|"+(string)avuuid+"|"+(string)statuscode, NULL_KEY);
  55. }
  56. // Send a translation request link message
  57. sloodle_translation_request(string output_method, list output_params, string string_name, list string_params, key keyval, string batch)
  58. {
  59. llMessageLinked(LINK_THIS, SLOODLE_CHANNEL_TRANSLATION_REQUEST, output_method + "|" + llList2CSV(output_params) + "|" + string_name + "|" + llList2CSV(string_params) + "|" + batch, keyval);
  60. }
  61. ///// ----------- /////
  62. sloodle_tell_other_scripts(string msg)
  63. {
  64. llMessageLinked(LINK_SET, SLOODLE_CHANNEL_OBJECT_DIALOG, msg, NULL_KEY);
  65. }
  66. sloodle_debug(string msg)
  67. {
  68. llMessageLinked(LINK_SET, DEBUG_CHANNEL, msg, NULL_KEY);
  69. }
  70. // Generate a random password string
  71. string sloodle_random_object_password()
  72. {
  73. return (string)(10000 + (integer)llFrand(999989999)); // Gets a random integer between 10000 and 999999999
  74. }
  75. // Load the authorisation URL
  76. sloodle_load_auth_url(key av)
  77. {
  78. sloodle_translation_request(SLOODLE_TRANSLATE_LOAD_URL, [sloodleauthurl], "userauthurl", [], av, "");
  79. }
  80. // Initiate an authorisation check.
  81. // Returns the key of the HTTP request.
  82. key sloodle_check_user_auth()
  83. {
  84. string body = "sloodleuuid=" + (string)llGetOwner();
  85. body += "&sloodlepwd=" + sloodlepwd;
  86. return llHTTPRequest(sloodleserverroot + SLOODLE_AUTH_CHECKER, [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"], body);
  87. }
  88. ///// STATES /////
  89. default
  90. {
  91. state_entry()
  92. {
  93. sloodle_debug("Setup user in default state.");
  94. // Pause for a moment, in case all scripts were reset at the same time
  95. llSleep(0.2);
  96. // Reset our data
  97. sloodleserverroot = "";
  98. sloodlepwd = "";
  99. sloodleauthurl = "";
  100. password = "";
  101. // Check to see if the server URL is in the object description
  102. string desc = llGetObjectDesc();
  103. if (desc != "" && llSubStringIndex(desc, "http") == 0) sloodleserverroot = desc;
  104. // Did we get a server root?
  105. if (sloodleserverroot == "") {
  106. // No - ask the owner for it
  107. llListen(0, "", llGetOwner(), "");
  108. llListen(1, "", llGetOwner(), "");
  109. sloodle_translation_request(SLOODLE_TRANSLATE_IM, [0], "chatserveraddress", [], llGetOwner(), "");
  110. sloodle_translation_request(SLOODLE_TRANSLATE_HOVER_TEXT, [<0.0,1.0,0.0>, 0.8], "waitingforserveraddress", [], NULL_KEY, "");
  111. } else {
  112. // Immediately start processing the Moodle site
  113. state check_moodle;
  114. }
  115. }
  116. state_exit()
  117. {
  118. llSetText("", <0.0,0.0,0.0>, 0.0);
  119. }
  120. listen(integer channel, string name, key id, string msg)
  121. {
  122. // Check the channel
  123. if (channel == 0 || channel == 1) {
  124. // Ignore anybody but the owner
  125. if (id != llGetOwner()) return;
  126. // If the message starts with "http" then store it as the Moodle address
  127. msg = llStringTrim(msg, STRING_TRIM);
  128. if (llSubStringIndex(msg, "http") == 0) {
  129. sloodleserverroot = msg;
  130. state check_moodle;
  131. return;
  132. }
  133. }
  134. }
  135. touch_start(integer num_detected)
  136. {
  137. if (llDetectedKey(0) == llGetOwner()) {
  138. // Remind the owner of what is needed
  139. sloodle_translation_request(SLOODLE_TRANSLATE_IM, [0], "chatserveraddress", [], llGetOwner(), "");
  140. }
  141. }
  142. link_message(integer sender_num, integer num, string sval, key kval)
  143. {
  144. // Check the channel
  145. if (num == SLOODLE_CHANNEL_OBJECT_DIALOG) {
  146. // Is it a reset command?
  147. if (sval == "do:reset") {
  148. llResetScript();
  149. return;
  150. }
  151. }
  152. }
  153. on_rez(integer start_param)
  154. {
  155. llResetScript();
  156. }
  157. attach( key av )
  158. {
  159. if (av != NULL_KEY)
  160. llResetScript();
  161. }
  162. }
  163. // Check that the Moodle site is valid
  164. state check_moodle
  165. {
  166. state_entry()
  167. {
  168. sloodle_debug("Checking Moodle...");
  169. sloodle_translation_request(SLOODLE_TRANSLATE_HOVER_TEXT, [<0.0,1.0,0.0>, 0.8], "checkingserverat", [sloodleserverroot], NULL_KEY, "");
  170. httpcheckmoodle = llHTTPRequest(sloodleserverroot + SLOODLE_VERSION_LINKER, [HTTP_METHOD, "GET"], "");
  171. }
  172. state_exit()
  173. {
  174. llSetText("", <0.0,0.0,0.0>, 0.0);
  175. httpcheckmoodle = NULL_KEY;
  176. }
  177. http_response(key id, integer status, list meta, string body)
  178. {
  179. // Make sure it's the response we're expecting
  180. if (id != httpcheckmoodle) return;
  181. httpcheckmoodle = NULL_KEY;
  182. // Check the status code
  183. if (status != 200) {
  184. sloodle_translation_request(SLOODLE_TRANSLATE_OWNER_SAY, [0], "httperror:code", [status], NULL_KEY, "");
  185. return;
  186. }
  187. // Split the response into lines and get the status line info
  188. list lines = llParseStringKeepNulls(body, ["\n"], []);
  189. integer numlines = llGetListLength(lines);
  190. list statusfields = llParseStringKeepNulls(llList2String(lines, 0), ["|"], []);
  191. integer statuscode = (integer)llList2String(statusfields, 0);
  192. // Make sure the status code was OK
  193. if (statuscode == -106) {
  194. sloodle_debug("ERROR -106: the Sloodle module is not installed on the specified Moodle site (" + sloodleserverroot + ")");
  195. sloodle_translation_request(SLOODLE_TRANSLATE_OWNER_SAY, [0], "sloodlenotinstalled", [], NULL_KEY, "");
  196. return;
  197. } else if (statuscode <= 0) {
  198. sloodle_translation_request(SLOODLE_TRANSLATE_OWNER_SAY, [0], "failedcheckcompatibility", [], NULL_KEY, "");
  199. sloodle_error_code(SLOODLE_TRANSLATE_SAY, NULL_KEY,statuscode); //send message to error_message.lsl
  200. return;
  201. }
  202. // Make sure we have enough other data
  203. if (numlines < 2) {
  204. sloodle_translation_request(SLOODLE_TRANSLATE_OWNER_SAY, [0], "badresponseformat", [], NULL_KEY, "");
  205. return;
  206. }
  207. // Extract the Sloodle version number
  208. list datafields = llParseStringKeepNulls(llList2String(lines, 1), ["|"], []);
  209. float installedversion = (float)llList2String(datafields, 0);
  210. // Check compatibility
  211. if (installedversion < SLOODLE_VERSION_MIN) {
  212. sloodle_translation_request(SLOODLE_TRANSLATE_OWNER_SAY, [0], "sloodleversioninstalled", [installedversion], NULL_KEY, "");
  213. sloodle_translation_request(SLOODLE_TRANSLATE_OWNER_SAY, [0], "sloodleversionrequired", [SLOODLE_VERSION_MIN], NULL_KEY, "");
  214. return;
  215. }
  216. // Initiate object authorisation
  217. state auth_object;
  218. }
  219. touch_start(integer num_detected)
  220. {
  221. // Revert to the default state if the owner touched
  222. if (llDetectedKey(0) != llGetOwner()) return;
  223. state default;
  224. }
  225. link_message(integer sender_num, integer num, string sval, key kval)
  226. {
  227. // Check the channel
  228. if (num == SLOODLE_CHANNEL_OBJECT_DIALOG) {
  229. // Is it a reset command?
  230. if (sval == "do:reset") {
  231. llResetScript();
  232. return;
  233. }
  234. }
  235. }
  236. on_rez(integer start_param)
  237. {
  238. llResetScript();
  239. }
  240. attach( key av )
  241. {
  242. if (av != NULL_KEY)
  243. llResetScript();
  244. }
  245. }
  246. // Object authorisation
  247. state auth_object
  248. {
  249. state_entry()
  250. {
  251. sloodle_debug("Object authorisation...");
  252. sloodle_translation_request(SLOODLE_TRANSLATE_HOVER_TEXT, [<0.0, 1.0, 0.0>, 0.8], "initobjectauth", [], NULL_KEY, "");
  253. // Generate a random password
  254. password = sloodle_random_object_password();
  255. sloodlepwd = (string)llGetKey() + "|" + password;
  256. // Initiate the object authorisation
  257. string body = "sloodleobjuuid=" + (string)llGetKey();
  258. body += "&sloodleobjname=" + llGetObjectName();
  259. body += "&sloodleobjpwd=" + password;
  260. body += "&sloodleuuid=" + (string)llGetOwner();
  261. body += "&sloodleavname=" + llEscapeURL(llKey2Name(llGetOwner()));
  262. httpauthobject = llHTTPRequest(sloodleserverroot + SLOODLE_USER_AUTH_LINKER, [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"], body);
  263. }
  264. state_exit()
  265. {
  266. llSetText("", <0.0,0.0,0.0>, 0.0);
  267. httpauthobject = NULL_KEY;
  268. }
  269. http_response(key id, integer status, list meta, string body)
  270. {
  271. // Make sure this is the response we're expecting
  272. if (id != httpauthobject) return;
  273. if (status != 200) {
  274. sloodle_translation_request(SLOODLE_TRANSLATE_OWNER_SAY, [0], "httperror:code", [status], NULL_KEY, "");
  275. return;
  276. }
  277. // Split the response into lines
  278. list lines = llParseStringKeepNulls(body, ["\n"], []);
  279. integer numlines = llGetListLength(lines);
  280. list statusfields = llParseStringKeepNulls(llList2String(lines, 0), ["|"], []);
  281. integer statuscode = (integer)llList2String(statusfields, 0);
  282. // Check the statuscode
  283. if (statuscode <= 0) {
  284. sloodle_translation_request(SLOODLE_TRANSLATE_OWNER_SAY, [0], "objectauthfailed:code", [statuscode], NULL_KEY, "");
  285. sloodle_error_code(SLOODLE_TRANSLATE_SAY, NULL_KEY,statuscode); //send message to error_message.lsl
  286. return;
  287. }
  288. // Attempt to get the auth ID
  289. if (numlines < 2) {
  290. sloodle_translation_request(SLOODLE_TRANSLATE_OWNER_SAY, [0], "badresponseformat", [], NULL_KEY, "");
  291. return;
  292. }
  293. // The dataline will contain our URL
  294. sloodleauthurl = llList2String(lines, 1);
  295. sloodle_load_auth_url(llGetOwner());
  296. state check_auth;
  297. }
  298. touch_start(integer num_detected)
  299. {
  300. // Revert to the default state if the owner touched
  301. if (llDetectedKey(0) != llGetOwner()) return;
  302. state default;
  303. }
  304. link_message(integer sender_num, integer num, string sval, key kval)
  305. {
  306. // Check the channel
  307. if (num == SLOODLE_CHANNEL_OBJECT_DIALOG) {
  308. // Is it a reset command?
  309. if (sval == "do:reset") {
  310. llResetScript();
  311. return;
  312. }
  313. }
  314. }
  315. on_rez(integer start_param)
  316. {
  317. state default;
  318. }
  319. attach( key av )
  320. {
  321. if (av != NULL_KEY)
  322. state default;
  323. }
  324. }
  325. // Check the object's authorisation status
  326. state check_auth
  327. {
  328. state_entry()
  329. {
  330. sloodle_translation_request(SLOODLE_TRANSLATE_OWNER_SAY, [], "checkingauth", [], NULL_KEY, "");
  331. // Check the authorisation regularly until it passes or we need to reset
  332. llSetTimerEvent(0.0);
  333. llSetTimerEvent(15.0);
  334. // Initiate the authorisation check
  335. httpcheckauth = sloodle_check_user_auth();
  336. }
  337. timer()
  338. {
  339. // Initiate the authorisation check
  340. httpcheckauth = sloodle_check_user_auth();
  341. }
  342. state_exit()
  343. {
  344. llSetTimerEvent(0.0);
  345. httpcheckauth = NULL_KEY;
  346. }
  347. http_response(key id, integer status, list meta, string body)
  348. {
  349. // Make sure this is the response we're expecting
  350. if (id != httpcheckauth) return;
  351. httpcheckauth = NULL_KEY;
  352. if (status != 200) {
  353. sloodle_translation_request(SLOODLE_TRANSLATE_OWNER_SAY, [], "httperror", [status], NULL_KEY, "");
  354. state idle;
  355. return;
  356. }
  357. // Split the response into lines
  358. list lines = llParseStringKeepNulls(body, ["\n"], []);
  359. integer numlines = llGetListLength(lines);
  360. list statusfields = llParseStringKeepNulls(llList2String(lines, 0), ["|"], []);
  361. integer statuscode = (integer)llList2String(statusfields, 0);
  362. // Check the statuscode.
  363. // If it reports that the object hasn't been authorised yet, then keep checking.
  364. // For any other error, go back to the start of the process.
  365. if (statuscode == -214) {
  366. sloodle_debug("Not authorised yet...");
  367. return;
  368. } else if (statuscode <= 0) {
  369. //sloodle_translation_request(SLOODLE_TRANSLATE_OWNER_SAY, [], "servererror", [statuscode], NULL_KEY, "");
  370. sloodle_error_code(SLOODLE_TRANSLATE_SAY, NULL_KEY,statuscode); //send message to error_message.lsl
  371. state default;
  372. return;
  373. }
  374. // Looks like we're authorised OK
  375. state send_config;
  376. }
  377. touch_start(integer num_detected)
  378. {
  379. // Initiate the authorisation check
  380. httpcheckauth = sloodle_check_user_auth();
  381. }
  382. link_message(integer sender_num, integer num, string sval, key kval)
  383. {
  384. // Check the channel
  385. if (num == SLOODLE_CHANNEL_OBJECT_DIALOG) {
  386. // Is it a reset command?
  387. if (sval == "do:reset") {
  388. llResetScript();
  389. return;
  390. }
  391. }
  392. }
  393. on_rez(integer start_param)
  394. {
  395. state default;
  396. }
  397. attach( key av )
  398. {
  399. if (av != NULL_KEY)
  400. state default;
  401. }
  402. }
  403. // Send the user to the authorisation page on the site.
  404. state send_config
  405. {
  406. state_entry()
  407. {
  408. sloodle_debug("Sending configuration...");
  409. // Send the configuration data to the other scripts
  410. string config = "set:sloodleserverroot|" + sloodleserverroot;
  411. config += "\nset:sloodlepwd|" + sloodlepwd;
  412. config += "\n" + SLOODLE_EOF;
  413. sloodle_tell_other_scripts(config);
  414. state idle;
  415. }
  416. }
  417. // Configuration finished
  418. state idle
  419. {
  420. state_entry()
  421. {
  422. sloodle_debug("Configuration finished.");
  423. }
  424. link_message(integer sender_num, integer num, string sval, key kval)
  425. {
  426. // Check the channel
  427. if (num == SLOODLE_CHANNEL_OBJECT_DIALOG) {
  428. // Check the command type
  429. if (sval == "do:reset") {
  430. llResetScript();
  431. } else if (sval == "do:requestconfig") {
  432. sloodle_debug("Configuration requested.");
  433. state check_auth;
  434. } else if (sval == "do:reconfigure") {
  435. sloodle_debug("Reconfiguration requested.");
  436. state default;
  437. }
  438. return;
  439. }
  440. }
  441. }
  442. // Please leave the following line intact to show where the script lives in Git:
  443. // SLOODLE LSL Script Git Location: assets/misc/sloodle_setup_user.lslp