1 /* IcedTeaPluginUtils.cc
2
3 Copyright (C) 2009, 2010 Red Hat
4
5 This file is part of IcedTea.
6
7 IcedTea is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 IcedTea is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with IcedTea; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
38
39 #include "IcedTeaNPPlugin.h"
40 #include "IcedTeaScriptablePluginObject.h"
41 #include "IcedTeaPluginUtils.h"
42 #include <fstream>
43
44 /**
45 * Misc. utility functions used by the plugin
46 */
47
48 /***********************************************
49 * Begin IcedTeaPluginUtilities implementation *
50 ************************************************/
51
52 // Initialize static variables
53 int IcedTeaPluginUtilities::reference = -1;
54 pthread_mutex_t IcedTeaPluginUtilities::reference_mutex = PTHREAD_MUTEX_INITIALIZER;
55 std::map<void*, NPP>* IcedTeaPluginUtilities::instance_map = new std::map<void*, NPP>();
56 std::map<std::string, NPObject*>* IcedTeaPluginUtilities::object_map = new std::map<std::string, NPObject*>();
57 std::queue<std::string> pre_jvm_message;
58
59 /* Plugin async call queue */
60 static std::vector< PluginThreadCall* >* pendingPluginThreadRequests = new std::vector< PluginThreadCall* >();
61
62 bool
create_dir(std::string dir)63 IcedTeaPluginUtilities::create_dir(std::string dir)
64 {
65 if (file_exists(dir))
66 {
67 if (!is_directory(dir))
68 {
69 PLUGIN_ERROR("WARNING: Needed to create directory %s but there is already a file of the same name at this location.\n", dir.c_str());
70 return false;
71 }
72 PLUGIN_DEBUG("Directory %s already exists\n", dir.c_str());
73 } else
74 {
75 PLUGIN_DEBUG("Directory %s does not yet exist\n", dir.c_str());
76 const int PERMISSIONS_MASK = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; // 0755
77 bool created_directory = (g_mkdir(dir.c_str(), PERMISSIONS_MASK) == 0);
78 int err = errno;
79 if (!created_directory)
80 {
81 PLUGIN_ERROR("WARNING: Failed to create new directory %s. Reason: %s\n", dir.c_str(), strerror(err));
82 return false;
83 }
84 PLUGIN_DEBUG("Directory %s created\n", dir.c_str());
85 }
86 return true;
87 }
88
flush_pre_init_messages(void * data)89 void *flush_pre_init_messages(void* data) {
90 while (true){
91 struct timespec ts;
92 ts.tv_sec = 1;
93 ts.tv_nsec = 0;
94 nanosleep(&ts ,0);
95 if (jvm_up) {
96 while (!pre_jvm_message.empty()) {
97 pthread_mutex_lock(&debug_pipe_lock);
98 std::string message = pre_jvm_message.front();
99 pre_jvm_message.pop();
100 pthread_mutex_unlock(&debug_pipe_lock);
101 plugin_send_message_to_appletviewer_console(message.c_str());
102 }
103 flush_plugin_send_message_to_appletviewer_console();
104 }
105 }
106 return NULL;
107 }
108
push_pre_init_messages(char * ldm)109 void push_pre_init_messages(char * ldm){
110 pthread_mutex_lock(&debug_pipe_lock);
111 pre_jvm_message.push(std::string(ldm));
112 pthread_mutex_unlock(&debug_pipe_lock);
113 }
114
reset_pre_init_messages()115 void reset_pre_init_messages(){
116 pre_jvm_message = std::queue<std::string>();
117 }
118
119 /**
120 * Given a context number, constructs a message prefix to send to Java
121 *
122 * @param context The context of the request
123 * @return The string prefix (allocated on heap)
124 */
125
126 void
constructMessagePrefix(int context,std::string * result)127 IcedTeaPluginUtilities::constructMessagePrefix(int context, std::string *result)
128 {
129 std::string context_str = std::string();
130
131 itoa(context, &context_str);
132
133 result->append("context ");
134 result->append(context_str);
135 result->append(" reference -1");
136
137 }
138
139 /**
140 * Given a context number, and reference number, constructs a message prefix to
141 * send to Java
142 *
143 * @param context The context of the request
144 * @param rerefence The reference number of the request
145 * @param result The message
146 */
147
148 void
constructMessagePrefix(int context,int reference,std::string * result)149 IcedTeaPluginUtilities::constructMessagePrefix(int context, int reference, std::string* result)
150 {
151 // Until security is implemented, use file:// source for _everything_
152
153 std::string context_str = std::string();
154 std::string reference_str = std::string();
155
156 itoa(context, &context_str);
157 itoa(reference, &reference_str);
158
159 *result += "context ";
160 result->append(context_str);
161 *result += " reference ";
162 result->append(reference_str);
163 }
164
165 /**
166 * Given a context number, reference number, and source location, constructs
167 * a message prefix to send to Java
168 *
169 * @param context The context of the request
170 * @param rerefence The reference number of the request
171 * @param address The address for the script that made the request
172 * @param result The message
173 */
174
175 void
constructMessagePrefix(int context,int reference,std::string address,std::string * result)176 IcedTeaPluginUtilities::constructMessagePrefix(int context, int reference,
177 std::string address,
178 std::string* result)
179 {
180 std::string context_str = std::string();
181 std::string reference_str = std::string();
182
183 itoa(context, &context_str);
184 itoa(reference, &reference_str);
185
186 *result += "context ";
187 result->append(context_str);
188 *result += " reference ";
189 result->append(reference_str);
190
191 if (address.length() > 0)
192 {
193 *result += " src ";
194 result->append(address);
195 }
196 }
197
198 /**
199 * Returns a string representation of a void pointer
200 *
201 * @param id The pointer
202 * @param result The string representation
203 */
204
205 void
JSIDToString(void * id,std::string * result)206 IcedTeaPluginUtilities::JSIDToString(void* id, std::string* result)
207 {
208 char id_str[NUM_STR_BUFFER_SIZE];
209
210 if (sizeof(void*) == sizeof(long long))
211 {
212 snprintf(id_str, NUM_STR_BUFFER_SIZE, "%llu", id);
213 }
214 else
215 {
216 snprintf(id_str, NUM_STR_BUFFER_SIZE, "%lu", id); // else use long
217 }
218
219 result->append(id_str);
220
221 PLUGIN_DEBUG("Converting pointer %p to %s\n", id, id_str);
222 }
223
224 /**
225 * Returns a void pointer from a string representation
226 *
227 * @param id_str The string representation
228 * @return The pointer
229 */
230
231 void*
stringToJSID(std::string id_str)232 IcedTeaPluginUtilities::stringToJSID(std::string id_str)
233 {
234 void* ptr;
235 if (sizeof(void*) == sizeof(long long))
236 {
237 PLUGIN_DEBUG("Casting (long long) \"%s\" -- %llu\n", id_str.c_str(), strtoull(id_str.c_str(), NULL, 0));
238 ptr = reinterpret_cast <void*> ((unsigned long long) strtoull(id_str.c_str(), NULL, 0));
239 } else
240 {
241 PLUGIN_DEBUG("Casting (long) \"%s\" -- %lu\n", id_str.c_str(), strtoul(id_str.c_str(), NULL, 0));
242 ptr = reinterpret_cast <void*> ((unsigned long) strtoul(id_str.c_str(), NULL, 0));
243 }
244
245 PLUGIN_DEBUG("Casted: %p\n", ptr);
246
247 return ptr;
248 }
249
250 /**
251 * Returns a void pointer from a string representation
252 *
253 * @param id_str The pointer to the string representation
254 * @return The pointer
255 */
256
257 void*
stringToJSID(std::string * id_str)258 IcedTeaPluginUtilities::stringToJSID(std::string* id_str)
259 {
260 void* ptr;
261 if (sizeof(void*) == sizeof(long long))
262 {
263 PLUGIN_DEBUG("Casting (long long) \"%s\" -- %llu\n", id_str->c_str(), strtoull(id_str->c_str(), NULL, 0));
264 ptr = reinterpret_cast <void*> ((unsigned long long) strtoull(id_str->c_str(), NULL, 0));
265 } else
266 {
267 PLUGIN_DEBUG("Casting (long) \"%s\" -- %lu\n", id_str->c_str(), strtoul(id_str->c_str(), NULL, 0));
268 ptr = reinterpret_cast <void*> ((unsigned long) strtoul(id_str->c_str(), NULL, 0));
269 }
270
271 PLUGIN_DEBUG("Casted: %p\n", ptr);
272
273 return ptr;
274 }
275
276 /**
277 * Increments the global reference number and returns it.
278 *
279 * This function is thread-safe.
280 */
281 int
getReference()282 IcedTeaPluginUtilities::getReference()
283 {
284 pthread_mutex_lock(&reference_mutex);
285
286 // If we are nearing the max, reset
287 if (reference < -0x7FFFFFFF + 10) {
288 reference = -1;
289 }
290
291 reference--;
292 pthread_mutex_unlock(&reference_mutex);
293
294 return reference;
295 }
296
297 /**
298 * Decrements the global reference number.
299 *
300 * This function is thread-safe.
301 */
302 void
releaseReference()303 IcedTeaPluginUtilities::releaseReference()
304 {
305 // do nothing for now
306 }
307
308 /**
309 * Converts integer to char*
310 *
311 * @param i The integer to convert to ascii
312 * @param result The resulting string
313 */
314 void
itoa(int i,std::string * result)315 IcedTeaPluginUtilities::itoa(int i, std::string* result)
316 {
317 char int_str[NUM_STR_BUFFER_SIZE];
318 snprintf(int_str, NUM_STR_BUFFER_SIZE, "%d", i);
319 result->append(int_str);
320 }
321
322 /**
323 * Frees memory from a string* vector
324 *
325 * The vector deconstructor will only delete string pointers upon being
326 * called. This function frees the associated string memory as well.
327 *
328 * @param v The vector whose strings are to be freed
329 */
330 void
freeStringPtrVector(std::vector<std::string * > * v)331 IcedTeaPluginUtilities::freeStringPtrVector(std::vector<std::string*>* v)
332 {
333 if (v)
334 {
335 for (int i=0; i < v->size(); i++) {
336 delete v->at(i);
337 }
338
339 delete v;
340 }
341
342 }
343
344 /**
345 * Given a string, splits it on the given delimiters.
346 *
347 * @param str The string to split
348 * @param The delimiters to split on
349 * @return A string vector containing the split components
350 */
351
352 std::vector<std::string*>*
strSplit(const char * str,const char * delim)353 IcedTeaPluginUtilities::strSplit(const char* str, const char* delim)
354 {
355 std::vector<std::string*>* v = new std::vector<std::string*>();
356 v->reserve(strlen(str)/2);
357 char* copy;
358
359 // Tokenization is done on a copy
360 copy = (char*) malloc (sizeof(char)*strlen(str) + 1);
361 strcpy(copy, str);
362
363 char* tok_ptr;
364 tok_ptr = strtok (copy, delim);
365
366 while (tok_ptr != NULL)
367 {
368 // Allocation on heap since caller has no way to knowing how much will
369 // be needed. Make sure caller cleans up!
370 std::string* s = new std::string();
371 s->append(tok_ptr);
372 v->push_back(s);
373 tok_ptr = strtok (NULL, delim);
374 }
375 free(copy);
376
377 return v;
378 }
379
380 /**
381 * Given a unicode byte array, converts it to a UTF8 string
382 *
383 * The actual contents in the array may be surrounded by other data.
384 *
385 * e.g. with length 5, begin = 3,
386 * unicode_byte_array = "37 28 5 48 45 4c 4c 4f 9e 47":
387 *
388 * We'd start at 3 i.e. "48" and go on for 5 i.e. upto and including "4f".
389 * So we convert "48 45 4c 4c 4f" which is "hello"
390 *
391 * @param length The length of the string
392 * @param begin Where in the array to begin conversion
393 * @param result_unicode_str The return variable in which the
394 * converted string is placed
395 */
396
397 void
getUTF8String(int length,int begin,std::vector<std::string * > * unicode_byte_array,std::string * result_unicode_str)398 IcedTeaPluginUtilities::getUTF8String(int length, int begin, std::vector<std::string*>* unicode_byte_array, std::string* result_unicode_str)
399 {
400 result_unicode_str->clear();
401 result_unicode_str->reserve(unicode_byte_array->size()/2);
402 for (int i = begin; i < begin+length; i++)
403 result_unicode_str->push_back((char) strtol(unicode_byte_array->at(i)->c_str(), NULL, 16));
404
405 PLUGIN_DEBUG("Converted UTF-8 string: %s. Length=%d\n", result_unicode_str->c_str(), result_unicode_str->length());
406 }
407
408 /**
409 * Given a UTF8 string, converts it to a space delimited string of hex characters
410 *
411 * The first element in the return array is the length of the string
412 *
413 * e.g. "hello" would convert to: "5 48 45 4c 4c 4f"
414 *
415 * @param str The string to convert
416 * @param urt_str The result
417 */
418
419 void
convertStringToUTF8(std::string * str,std::string * utf_str)420 IcedTeaPluginUtilities::convertStringToUTF8(std::string* str, std::string* utf_str)
421 {
422 std::ostringstream ostream;
423
424 std::string length = std::string();
425 itoa(str->length(), &length);
426
427 ostream << length;
428
429 char hex_value[NUM_STR_BUFFER_SIZE];
430
431 for (int i = 0; i < str->length(); i++)
432 {
433 snprintf(hex_value, NUM_STR_BUFFER_SIZE," %hx", str->at(i));
434 ostream << hex_value;
435 }
436
437 utf_str->clear();
438 *utf_str = ostream.str();
439
440 PLUGIN_DEBUG("Converted %s to UTF-8 string %s\n", str->c_str(), utf_str->c_str());
441 }
442
443 /**
444 * Given a unicode byte array, converts it to a UTF16LE/UCS-2 string
445 *
446 * This works in a manner similar to getUTF8String, except that it reads 2
447 * slots for each byte.
448 *
449 * @param length The length of the string
450 * @param begin Where in the array to begin conversion
451 * @param result_unicode_str The return variable in which the
452 * converted string is placed
453 */
454 void
getUTF16LEString(int length,int begin,std::vector<std::string * > * unicode_byte_array,std::wstring * result_unicode_str)455 IcedTeaPluginUtilities::getUTF16LEString(int length, int begin, std::vector<std::string*>* unicode_byte_array, std::wstring* result_unicode_str)
456 {
457
458 wchar_t c;
459
460 PLUGIN_DEBUG("Converted UTF-16LE string: \n");
461
462 result_unicode_str->clear();
463 for (int i = begin; i < begin+length; i+=2)
464 {
465 int low = strtol(unicode_byte_array->at(i)->c_str(), NULL, 16);
466 int high = strtol(unicode_byte_array->at(i+1)->c_str(), NULL, 16);
467
468 c = ((high << 8) | low);
469
470 if ((c >= 'a' && c <= 'z') ||
471 (c >= 'A' && c <= 'Z') ||
472 (c >= '0' && c <= '9'))
473 {
474 PLUGIN_DEBUG("%c\n", c);
475 }
476
477 result_unicode_str->push_back(c);
478 }
479
480 // not routing via debug print macros due to wide-string issues
481 PLUGIN_DEBUG(". Length=%d\n", result_unicode_str->length());
482 }
483
484 /*
485 * Prints the given string vector (if debug is true)
486 *
487 * @param prefix The prefix to print before printing the vector contents
488 * @param cv The string vector whose contents are to be printed
489 */
490 void
printStringVector(const char * prefix,std::vector<std::string> * str_vector)491 IcedTeaPluginUtilities::printStringVector(const char* prefix, std::vector<std::string>* str_vector)
492 {
493
494 // This is a CPU intensive function. Run only if debugging
495 if (!plugin_debug)
496 return;
497
498 std::string* str = new std::string();
499 *str += "{ ";
500 for (int i=0; i < str_vector->size(); i++)
501 {
502 *str += str_vector->at(i);
503
504 if (i != str_vector->size() - 1)
505 *str += ", ";
506 }
507
508 *str += " }";
509
510 PLUGIN_DEBUG("%s %s\n", prefix, str->c_str());
511
512 delete str;
513 }
514
515 const gchar*
getSourceFromInstance(NPP instance)516 IcedTeaPluginUtilities::getSourceFromInstance(NPP instance)
517 {
518 // At the moment, src cannot be securely fetched via NPAPI
519 // See:
520 // http://www.mail-archive.com/chromium-dev@googlegroups.com/msg04872.html
521
522 // Since we use the insecure window.location.href attribute to compute
523 // source, we cannot use it to make security decisions. Therefore,
524 // instance associated source will always return empty
525
526 //ITNPPluginData* data = (ITNPPluginData*) instance->pdata;
527 //return (data->source) ? data->source : "";
528
529 return "http://null.null";
530 }
531
532 /**
533 * Stores a window pointer <-> instance mapping
534 *
535 * @param member_ptr The pointer key
536 * @param instance The instance to associate with this pointer
537 */
538
539 void
storeInstanceID(void * member_ptr,NPP instance)540 IcedTeaPluginUtilities::storeInstanceID(void* member_ptr, NPP instance)
541 {
542 PLUGIN_DEBUG("Storing instance %p with key %p\n", instance, member_ptr);
543 instance_map->insert(std::make_pair(member_ptr, instance));
544 }
545
546 /**
547 * Removes a window pointer <-> instance mapping
548 *
549 * @param member_ptr The key to remove
550 */
551
552 void
removeInstanceID(void * member_ptr)553 IcedTeaPluginUtilities::removeInstanceID(void* member_ptr)
554 {
555 PLUGIN_DEBUG("Removing key %p from instance map\n", member_ptr);
556 instance_map->erase(member_ptr);
557 }
558
559 /* Clear instance_map. Useful for tests. */
560 void
clearInstanceIDs()561 IcedTeaPluginUtilities::clearInstanceIDs()
562 {
563 delete instance_map;
564 instance_map = new std::map<void*, NPP>();
565 }
566
567 /**
568 * Removes all mappings to a given instance, and all associated objects
569 */
570 void
invalidateInstance(NPP instance)571 IcedTeaPluginUtilities::invalidateInstance(NPP instance)
572 {
573 PLUGIN_DEBUG("Invalidating instance %p\n", instance);
574
575 std::map<void*,NPP>::iterator iterator;
576
577 for (iterator = instance_map->begin(); iterator != instance_map->end(); )
578 {
579 if ((*iterator).second == instance)
580 {
581 instance_map->erase(iterator++);
582 }
583 else
584 {
585 ++iterator;
586 }
587 }
588 }
589
590 /**
591 * Given the window pointer, returns the instance associated with it
592 *
593 * @param member_ptr The pointer key
594 * @return The associated instance
595 */
596
597 NPP
getInstanceFromMemberPtr(void * member_ptr)598 IcedTeaPluginUtilities::getInstanceFromMemberPtr(void* member_ptr)
599 {
600
601 NPP instance = NULL;
602 PLUGIN_DEBUG("getInstanceFromMemberPtr looking for %p\n", member_ptr);
603
604 std::map<void*, NPP>::iterator iterator = instance_map->find(member_ptr);
605
606 if (iterator != instance_map->end())
607 {
608 instance = instance_map->find(member_ptr)->second;
609 PLUGIN_DEBUG("getInstanceFromMemberPtr found %p. Instance = %p\n", member_ptr, instance);
610 }
611
612 return instance;
613 }
614
615 /**
616 * Given a java id key ('classid:instanceid'), returns the associated valid NPObject, if any
617 *
618 * @param key the key
619 * @return The associated active NPObject, NULL otherwise
620 */
621
622 NPObject*
getNPObjectFromJavaKey(std::string key)623 IcedTeaPluginUtilities::getNPObjectFromJavaKey(std::string key)
624 {
625
626 NPObject* object = NULL;
627 PLUGIN_DEBUG("getNPObjectFromJavaKey looking for %s\n", key.c_str());
628
629 std::map<std::string, NPObject*>::iterator iterator = object_map->find(key);
630
631 if (iterator != object_map->end())
632 {
633 NPObject* mapped_object = object_map->find(key)->second;
634
635 if (getInstanceFromMemberPtr(mapped_object) != NULL)
636 {
637 object = mapped_object;
638 PLUGIN_DEBUG("getNPObjectFromJavaKey found %s. NPObject = %p\n", key.c_str(), object);
639 }
640 }
641
642 return object;
643 }
644
645 /**
646 * Stores a java id key <-> NPObject mapping
647 *
648 * @param key The Java ID Key
649 * @param object The object to map to
650 */
651
652 void
storeObjectMapping(std::string key,NPObject * object)653 IcedTeaPluginUtilities::storeObjectMapping(std::string key, NPObject* object)
654 {
655 PLUGIN_DEBUG("Storing object %p with key %s\n", object, key.c_str());
656 object_map->insert(std::make_pair(key, object));
657 }
658
659 /**
660 * Removes a java id key <-> NPObject mapping
661 *
662 * @param key The key to remove
663 */
664
665 void
removeObjectMapping(std::string key)666 IcedTeaPluginUtilities::removeObjectMapping(std::string key)
667 {
668 PLUGIN_DEBUG("Removing key %s from object map\n", key.c_str());
669 object_map->erase(key);
670 }
671
672 /* Clear object_map. Useful for tests. */
673 void
clearObjectMapping()674 IcedTeaPluginUtilities::clearObjectMapping()
675 {
676 std::map<std::string, NPObject*>::iterator iter = object_map->begin();
677 for (; iter != object_map->end(); ++iter) {
678 browser_functions.releaseobject(iter->second);
679 }
680 delete object_map;
681 object_map = new std::map<std::string, NPObject*>();
682 }
683
684 /*
685 * Similar to printStringVector, but takes a vector of string pointers instead
686 *
687 * @param prefix The prefix to print before printing the vector contents
688 * @param cv The string* vector whose contents are to be printed
689 */
690
691 void
printStringPtrVector(const char * prefix,std::vector<std::string * > * str_ptr_vector)692 IcedTeaPluginUtilities::printStringPtrVector(const char* prefix, std::vector<std::string*>* str_ptr_vector)
693 {
694 // This is a CPU intensive function. Run only if debugging
695 if (!plugin_debug)
696 return;
697
698 std::string* str = new std::string();
699 *str += "{ ";
700 for (int i=0; i < str_ptr_vector->size(); i++)
701 {
702 *str += *(str_ptr_vector->at(i));
703
704 if (i != str_ptr_vector->size() - 1)
705 *str += ", ";
706 }
707
708 *str += " }";
709
710 PLUGIN_DEBUG("%s %s\n", prefix, str->c_str());
711
712 delete str;
713 }
714
715 void
printNPVariant(NPVariant variant)716 IcedTeaPluginUtilities::printNPVariant(NPVariant variant)
717 {
718 // This is a CPU intensive function. Run only if debugging
719 if (!plugin_debug)
720 return;
721
722 if (NPVARIANT_IS_VOID(variant))
723 {
724 PLUGIN_DEBUG("VOID %d\n", variant);
725 }
726 else if (NPVARIANT_IS_NULL(variant))
727 {
728 PLUGIN_DEBUG("NULL\n", variant);
729 }
730 else if (NPVARIANT_IS_BOOLEAN(variant))
731 {
732 PLUGIN_DEBUG("BOOL: %d\n", NPVARIANT_TO_BOOLEAN(variant));
733 }
734 else if (NPVARIANT_IS_INT32(variant))
735 {
736 PLUGIN_DEBUG("INT32: %d\n", NPVARIANT_TO_INT32(variant));
737 }
738 else if (NPVARIANT_IS_DOUBLE(variant))
739 {
740 PLUGIN_DEBUG("DOUBLE: %f\n", NPVARIANT_TO_DOUBLE(variant));
741 }
742 else if (NPVARIANT_IS_STRING(variant))
743 {
744 std::string str = IcedTeaPluginUtilities::NPVariantAsString(variant);
745 PLUGIN_DEBUG("STRING: %s (length=%d)\n", str.c_str(), str.size());
746 }
747 else
748 {
749 PLUGIN_DEBUG("OBJ: %p\n", NPVARIANT_TO_OBJECT(variant));
750 }
751 }
752
753 void
NPVariantToString(NPVariant variant,std::string * result)754 IcedTeaPluginUtilities::NPVariantToString(NPVariant variant, std::string* result)
755 {
756 char conv_str[NUM_STR_BUFFER_SIZE]; // conversion buffer
757 bool was_string_already = false;
758
759 if (NPVARIANT_IS_STRING(variant))
760 {
761 result->append(IcedTeaPluginUtilities::NPVariantAsString(variant));
762 was_string_already = true;
763 }
764 else if (NPVARIANT_IS_VOID(variant))
765 {
766 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "%p", variant);
767 }
768 else if (NPVARIANT_IS_NULL(variant))
769 {
770 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "NULL");
771 }
772 else if (NPVARIANT_IS_BOOLEAN(variant))
773 {
774 if (NPVARIANT_TO_BOOLEAN(variant))
775 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "true");
776 else
777 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "false");
778 }
779 else if (NPVARIANT_IS_INT32(variant))
780 {
781 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "%d", NPVARIANT_TO_INT32(variant));
782 }
783 else if (NPVARIANT_IS_DOUBLE(variant))
784 {
785 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "%f", NPVARIANT_TO_DOUBLE(variant));
786 }
787 else
788 {
789 snprintf(conv_str, NUM_STR_BUFFER_SIZE, "[Object %p]", variant);
790 }
791
792 if (!was_string_already){
793 result->append(conv_str);
794 }
795 }
796
797 /**
798 * Convert either a void, boolean, or a number
799 */
800 static void
javaPrimitiveResultToNPVariant(const std::string & value,NPVariant * variant)801 javaPrimitiveResultToNPVariant(const std::string& value, NPVariant* variant)
802 {
803 if (value == "void")
804 {
805 PLUGIN_DEBUG("Method call returned void\n");
806 VOID_TO_NPVARIANT(*variant);
807 } else if (value == "null")
808 {
809 PLUGIN_DEBUG("Method call returned null\n");
810 NULL_TO_NPVARIANT(*variant);
811 } else if (value == "true")
812 {
813 PLUGIN_DEBUG("Method call returned a boolean (true)\n");
814 BOOLEAN_TO_NPVARIANT(true, *variant);
815 } else if (value == "false")
816 {
817 PLUGIN_DEBUG("Method call returned a boolean (false)\n");
818 BOOLEAN_TO_NPVARIANT(false, *variant);
819 } else
820 {
821 double d = strtod(value.c_str(), NULL);
822
823 // See if it is convertible to int
824 if (value.find(".") != std::string::npos || d < -(0x7fffffffL - 1L) || d > 0x7fffffffL)
825 {
826 PLUGIN_DEBUG("Method call returned a double %f\n", d);
827 DOUBLE_TO_NPVARIANT(d, *variant);
828 } else
829 {
830 int32_t i = (int32_t) d;
831 PLUGIN_DEBUG("Method call returned an int %d\n", i);
832 INT32_TO_NPVARIANT(i, *variant);
833 }
834 }
835 }
836
837 static bool
javaStringResultToNPVariant(const std::string & jobject_id,NPVariant * variant)838 javaStringResultToNPVariant(const std::string& jobject_id, NPVariant* variant)
839 {
840 JavaRequestProcessor jrequest_processor;
841 JavaResultData* jstring_result = jrequest_processor.getString(jobject_id);
842
843 if (jstring_result->error_occurred)
844 {
845 return false;
846 }
847
848 std::string str = *jstring_result->return_string;
849
850 PLUGIN_DEBUG( "Method call returned a string:\"%s\"\n", str.c_str());
851
852 *variant = IcedTeaPluginUtilities::NPVariantStringCopy(str);
853
854 return true;
855 }
856
857 static bool
javaJSObjectResultToNPVariant(const std::string & js_id,NPVariant * variant)858 javaJSObjectResultToNPVariant(const std::string& js_id, NPVariant* variant)
859 {
860 NPVariant* result_variant = (NPVariant*) IcedTeaPluginUtilities::stringToJSID(js_id);
861 *variant = *result_variant;
862 return true;
863 }
864
865 static bool
javaObjectResultToNPVariant(NPP instance,const std::string & jclass_name,const std::string & jobject_id,NPVariant * variant)866 javaObjectResultToNPVariant(NPP instance, const std::string& jclass_name, const std::string& jobject_id, NPVariant* variant)
867 {
868 // Reference the class object so we can construct an NPObject with it and the instance
869
870 JavaRequestProcessor jrequest_processor;
871 JavaResultData* jclass_result = jrequest_processor.getClassID(jobject_id);
872
873 if (jclass_result->error_occurred)
874 {
875 return false;
876 }
877
878 std::string jclass_id = *jclass_result->return_string;
879
880 NPObject* obj;
881 if (jclass_name.at(0) == '[') // array
882 {
883 PLUGIN_DEBUG( "javaObjectResultToNPVariant Array detected: \"%s\"\n", jclass_name.c_str());
884 obj = IcedTeaScriptableJavaObject::get_scriptable_java_object(instance, jclass_id,
885 jobject_id, true);
886 } else
887 {
888 PLUGIN_DEBUG( "javaObjectResultToNPVariant Scalar object: \"%s\"\n", jclass_name.c_str());
889 obj = IcedTeaScriptableJavaObject::get_scriptable_java_object(instance, jclass_id,
890 jobject_id, false);
891 }
892
893 OBJECT_TO_NPVARIANT(obj, *variant);
894
895 return true;
896 }
897
898 bool
javaResultToNPVariant(NPP instance,std::string * java_value,NPVariant * variant)899 IcedTeaPluginUtilities::javaResultToNPVariant(NPP instance,
900 std::string* java_value, NPVariant* variant)
901 {
902 int literal_n = sizeof("literalreturn"); // Accounts for one space char
903 int jsobject_n = sizeof("jsobject"); // Accounts for one space char
904
905 if (strncmp("literalreturn ", java_value->c_str(), literal_n) == 0)
906 {
907 javaPrimitiveResultToNPVariant(java_value->substr(literal_n), variant);
908 } else if (strncmp("jsobject ", java_value->c_str(), jsobject_n) == 0)
909 {
910 javaJSObjectResultToNPVariant(java_value->substr(jsobject_n), variant);
911 } else
912 {
913 std::string jobject_id = *java_value;
914
915 JavaRequestProcessor jrequest_processor;
916 JavaResultData* jclassname_result = jrequest_processor.getClassName(jobject_id);
917
918 if (jclassname_result->error_occurred)
919 {
920 return false;
921 }
922
923 // Special-case for NPString if string
924 if (*jclassname_result->return_string == "java.lang.String")
925 {
926 return javaStringResultToNPVariant(jobject_id, variant);
927 } else // Else this needs a java object wrapper
928 {
929 return javaObjectResultToNPVariant(instance, *jclassname_result->return_string,
930 jobject_id, variant);
931 }
932 }
933
934 return true;
935 }
936
937 bool
isObjectJSArray(NPP instance,NPObject * object)938 IcedTeaPluginUtilities::isObjectJSArray(NPP instance, NPObject* object)
939 {
940
941 NPVariant constructor_v = NPVariant();
942 NPIdentifier constructor_id = browser_functions.getstringidentifier("constructor");
943 browser_functions.getproperty(instance, object, constructor_id, &constructor_v);
944 IcedTeaPluginUtilities::printNPVariant(constructor_v);
945
946 // void constructor => not an array
947 if (NPVARIANT_IS_VOID(constructor_v))
948 return false;
949
950 NPObject* constructor = NPVARIANT_TO_OBJECT(constructor_v);
951
952 NPVariant constructor_str;
953 NPIdentifier toString = browser_functions.getstringidentifier("toString");
954 browser_functions.invoke(instance, constructor, toString, NULL, 0, &constructor_str);
955 IcedTeaPluginUtilities::printNPVariant(constructor_str);
956
957 std::string constructor_name = IcedTeaPluginUtilities::NPVariantAsString(constructor_str);
958
959 PLUGIN_DEBUG("Constructor for NPObject is %s\n", constructor_name.c_str());
960
961 return constructor_name.find("function Array") == 0;
962 }
963
964 void
decodeURL(const gchar * url,gchar ** decoded_url)965 IcedTeaPluginUtilities::decodeURL(const gchar* url, gchar** decoded_url)
966 {
967
968 PLUGIN_DEBUG("GOT URL: %s -- %s\n", url, *decoded_url);
969 int length = strlen(url);
970 for (int i=0; i < length; i++)
971 {
972 if (url[i] == '%' && i < length - 2)
973 {
974 unsigned char code1 = (unsigned char) url[i+1];
975 unsigned char code2 = (unsigned char) url[i+2];
976
977 if (!IS_VALID_HEX(&code1) || !IS_VALID_HEX(&code2))
978 continue;
979
980 // Convert hex value to integer
981 int converted1 = HEX_TO_INT(&code1);
982 int converted2 = HEX_TO_INT(&code2);
983
984 // bitshift 4 to simulate *16
985 int value = (converted1 << 4) + converted2;
986 char decoded = value;
987
988 strncat(*decoded_url, &decoded, 1);
989
990 i += 2;
991 } else
992 {
993 strncat(*decoded_url, &url[i], 1);
994 }
995 }
996
997 PLUGIN_DEBUG("SENDING URL: %s\n", *decoded_url);
998 }
999
1000 /* Copies a variant data type into a C++ string */
1001 std::string
NPVariantAsString(NPVariant variant)1002 IcedTeaPluginUtilities::NPVariantAsString(NPVariant variant)
1003 {
1004 return std::string(
1005 NPVARIANT_TO_STRING(variant).UTF8Characters,
1006 NPVARIANT_TO_STRING(variant).UTF8Length);
1007 }
1008
1009 /**
1010 * Posts a function for execution on the plug-in thread and wait for result.
1011 *
1012 * @param instance The NPP instance
1013 * @param func The function to post
1014 * @param data Arguments to *func
1015 */
NPStringCopy(const std::string & result)1016 NPString IcedTeaPluginUtilities::NPStringCopy(const std::string& result) {
1017 char* utf8 = (char*)browser_functions.memalloc(result.size() + 1);
1018 strncpy(utf8, result.c_str(), result.size() + 1);
1019
1020 NPString npstr = {utf8, (uint32_t)result.size()};
1021 return npstr;
1022 }
1023
NPVariantStringCopy(const std::string & result)1024 NPVariant IcedTeaPluginUtilities::NPVariantStringCopy(const std::string& result) {
1025 NPString npstr = NPStringCopy(result);
1026 NPVariant npvar;
1027 STRINGN_TO_NPVARIANT(npstr.UTF8Characters, npstr.UTF8Length, npvar);
1028 return npvar;
1029 }
1030
1031 void
callAndWaitForResult(NPP instance,void (* func)(void *),AsyncCallThreadData * data)1032 IcedTeaPluginUtilities::callAndWaitForResult(NPP instance, void (*func) (void *), AsyncCallThreadData* data)
1033 {
1034
1035 struct timespec t;
1036 struct timespec curr_t;
1037 clock_gettime(CLOCK_REALTIME, &t);
1038 t.tv_sec += REQUESTTIMEOUT; // timeout
1039
1040 // post request
1041 postPluginThreadAsyncCall(instance, func, data);
1042
1043 do
1044 {
1045 clock_gettime(CLOCK_REALTIME, &curr_t);
1046 if (data != NULL && !data->result_ready && (curr_t.tv_sec < t.tv_sec))
1047 {
1048 usleep(2000);
1049 } else
1050 {
1051 break;
1052 }
1053 } while (1);
1054 }
1055
1056
1057 /**
1058 * Posts a request that needs to be handled in a plugin thread.
1059 *
1060 * @param instance The plugin instance
1061 * @param func The function to execute
1062 * @param userData The userData for the function to consume/write to
1063 * @return if the call was posted successfully
1064 */
1065
1066 bool
postPluginThreadAsyncCall(NPP instance,void (* func)(void *),void * data)1067 IcedTeaPluginUtilities::postPluginThreadAsyncCall(NPP instance, void (*func) (void *), void* data)
1068 {
1069 if (instance)
1070 {
1071 PluginThreadCall* call = new PluginThreadCall();
1072 call->instance = instance;
1073 call->func = func;
1074 call->userData = data;
1075
1076 pthread_mutex_lock(&pluginAsyncCallMutex);
1077 pendingPluginThreadRequests->push_back(call);
1078 pthread_mutex_unlock(&pluginAsyncCallMutex);
1079
1080 browser_functions.pluginthreadasynccall(instance, &processAsyncCallQueue, NULL); // Always returns immediately
1081
1082 PLUGIN_DEBUG("Pushed back call evt %p\n", call);
1083
1084 return true;
1085 }
1086
1087 // Else
1088 PLUGIN_DEBUG("Instance is not active. Call rejected.\n");
1089 return false;
1090 }
1091
1092 /**
1093 * Returns a vector of gchar* pointing to the elements of the vector string passed in.
1094 * @param stringVec The vector of strings reference.
1095 */
1096 std::vector<gchar*>
vectorStringToVectorGchar(const std::vector<std::string> * stringVec)1097 IcedTeaPluginUtilities::vectorStringToVectorGchar(const std::vector<std::string>* stringVec)
1098 {
1099 std::vector<gchar*> charVec;
1100
1101 for (int i = 0; i < stringVec->size(); i++)
1102 {
1103 gchar* element = (gchar*) stringVec->at(i).c_str(); //cast from const char
1104 charVec.push_back(element);
1105 }
1106 charVec.push_back(NULL);
1107 return charVec;
1108 }
1109
1110 /**
1111 * Runs through the async call wait queue and executes all calls
1112 *
1113 * @param param Ignored -- required to conform to NPN_PluginThreadAsynCall API
1114 */
1115 void
processAsyncCallQueue(void * param)1116 processAsyncCallQueue(void* param /* ignored */)
1117 {
1118 do {
1119 PluginThreadCall* call = NULL;
1120
1121 pthread_mutex_lock(&pluginAsyncCallMutex);
1122 if (pendingPluginThreadRequests->size() > 0)
1123 {
1124 call = pendingPluginThreadRequests->front();
1125 pendingPluginThreadRequests->erase(pendingPluginThreadRequests->begin());
1126 }
1127 pthread_mutex_unlock(&pluginAsyncCallMutex);
1128
1129 if (call)
1130 {
1131 PLUGIN_DEBUG("Processing call evt %p\n", call);
1132 call->func(call->userData);
1133 PLUGIN_DEBUG("Call evt %p processed\n", call);
1134
1135 delete call;
1136 } else
1137 {
1138 break;
1139 }
1140 } while(1);
1141 }
1142
trim(std::string & str)1143 void IcedTeaPluginUtilities::trim(std::string& str) {
1144 size_t start = str.find_first_not_of(" \t\n"), end = str.find_last_not_of(" \t\n");
1145 if (start == std::string::npos) {
1146 return;
1147 }
1148 str = str.substr(start, end - start + 1);
1149 }
1150
1151 /*Unescape various escaped chars like \\ -> \ or \= -> = or \: -> , \t -> TAB , \n -> NwLine\*/
1152
1153 /* examples
1154 * \\= -> \=
1155 * \= -> =
1156 * \\ -> \
1157 * \e -> \e
1158 * \: -> :
1159 * \ -> \
1160 * \\ -> \
1161 */
unescape(std::string & str)1162 void IcedTeaPluginUtilities::unescape(std::string& str) {
1163 std::string result = "";
1164 int len = str.length();
1165 for (unsigned int i = 0; i < len; i++) {
1166 bool processed = false;
1167 char c1 = str[i];
1168 if (c1 == '\\') {
1169 if (i < len - 1) {
1170 char c2 = str[i + 1];
1171 if (c2 == '=' || c2 == '\\' || c2 == ':') {
1172 result += c2;
1173 i++;
1174 processed = true;
1175 }
1176 if (c2 == 't') {
1177 result += '\t';
1178 i++;
1179 processed = true;
1180 }
1181 if (c2 == 'n') {
1182 result += '\n';
1183 i++;
1184 processed = true;
1185 }
1186 if (c2 == 'r') {
1187 result += '\r';
1188 i++;
1189 processed = true;
1190 }
1191 }
1192 }
1193 if (!processed) {
1194 result += c1;
1195 }
1196 }
1197 str = result;
1198 }
1199
NPIdentifierAsString(NPIdentifier id)1200 std::string IcedTeaPluginUtilities::NPIdentifierAsString(NPIdentifier id) {
1201 NPUTF8* cstr = browser_functions.utf8fromidentifier(id);
1202 if (cstr == NULL) {
1203 /* Treat not-existing strings as empty. To tell if it was a valid string,
1204 * use browser_functions.identifierisstring. */
1205 return std::string();
1206 }
1207 std::string str = cstr;
1208 browser_functions.memfree(cstr);
1209 return str;
1210 }
1211
file_exists(std::string filename)1212 bool IcedTeaPluginUtilities::file_exists(std::string filename)
1213 {
1214 std::ifstream infile(filename.c_str());
1215 return infile.good();
1216 }
1217
is_directory(std::string filename)1218 bool IcedTeaPluginUtilities::is_directory(std::string filename)
1219 {
1220 if (!file_exists)
1221 {
1222 return false;
1223 }
1224 struct stat buf;
1225 stat(filename.c_str(), &buf);
1226 return S_ISDIR(buf.st_mode);
1227 }
1228
initFileLog()1229 void IcedTeaPluginUtilities::initFileLog(){
1230 if (plugin_file_log != NULL ) {
1231 //reusing
1232 return;
1233 }
1234 plugin_file_log_name = get_log_dir() + "/" + IcedTeaPluginUtilities::generateLogFileName();
1235 int plugin_file_log_fd = open(plugin_file_log_name.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600);
1236 if (plugin_file_log_fd <=0 ) {
1237 plugin_debug_to_file = false;
1238 } else {
1239 plugin_file_log = fdopen(plugin_file_log_fd, "w");
1240 }
1241 if (plugin_file_log == NULL ) {
1242 plugin_debug_to_file = false;
1243 }
1244 }
1245
1246
1247
generateLogFileName()1248 std::string IcedTeaPluginUtilities::generateLogFileName(){
1249 char times[96];
1250 char result[100];
1251 time_t t = time(NULL);
1252 struct tm p;
1253 localtime_r(&t, &p);
1254 struct timeval current_time; \
1255 gettimeofday (¤t_time, NULL);\
1256 strftime(times, 96, "%Y-%m-%d_%H:%M:%S", &p);
1257 snprintf(result, 100, "%s.%i",times, current_time.tv_usec/1000);
1258 return "itw-cplugin-"+std::string(result)+".log";
1259 }
1260
printDebugStatus()1261 void IcedTeaPluginUtilities::printDebugStatus(){
1262 if (plugin_debug){
1263 PLUGIN_DEBUG("plugin_debug: true, initialised\n");
1264 if (plugin_debug_headers){
1265 PLUGIN_DEBUG("plugin_debug_headers: true\n");
1266 } else {
1267 PLUGIN_DEBUG("plugin_debug_headers: false\n");
1268 }
1269 if (plugin_debug_to_file){
1270 PLUGIN_DEBUG("plugin_debug_to_file: true, using %s\n", plugin_file_log_name.c_str());
1271 } else {
1272 PLUGIN_DEBUG("plugin_debug_to_file: false\n");
1273 }
1274 if (plugin_debug_to_streams){
1275 PLUGIN_DEBUG("plugin_debug_to_streams: true\n");
1276 } else {
1277 PLUGIN_DEBUG("plugin_debug_to_streams: false\n");
1278 }
1279 if (plugin_debug_to_system){
1280 PLUGIN_DEBUG("plugin_debug_to_system: true\n");
1281 } else {
1282 PLUGIN_DEBUG("plugin_debug_to_system: false\n");
1283 }
1284 if (plugin_debug_to_console){
1285 if (debug_pipe_name){
1286 PLUGIN_DEBUG("plugin_debug_to_console: true, pipe %s\n", debug_pipe_name);
1287 } else {
1288 PLUGIN_DEBUG("plugin_debug_to_console: true, pipe not yet known or broken\n");
1289 }
1290 } else {
1291 PLUGIN_DEBUG("plugin_debug_to_console: false\n");
1292 }
1293 }
1294 }
1295
1296
getTmpPath()1297 std::string IcedTeaPluginUtilities::getTmpPath(){
1298 const char* tmpdir_env = getenv("TMPDIR");
1299 if (tmpdir_env != NULL && g_file_test (tmpdir_env,
1300 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
1301 {
1302 return std::string(tmpdir_env);
1303 }
1304 else if (g_file_test (P_tmpdir,
1305 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
1306 {
1307 return std::string(P_tmpdir);
1308 }
1309 else
1310 {
1311 // If TMPDIR and P_tmpdir do not exist, try /tmp directly
1312 return "/tmp";
1313 }
1314 }
1315
getRuntimePath()1316 std::string IcedTeaPluginUtilities::getRuntimePath(){
1317 const char* rntdir_env = getenv("XDG_RUNTIME_DIR");
1318 if (rntdir_env != NULL && g_file_test (rntdir_env,
1319 (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
1320 {
1321 return std::string(rntdir_env);
1322 }
1323 return IcedTeaPluginUtilities::getTmpPath();
1324 }
1325
1326
1327 /******************************************
1328 * Begin JavaMessageSender implementation *
1329 ******************************************
1330 *
1331 * This implementation is very simple and is therefore folded into this file
1332 * rather than a new one.
1333 */
1334
1335 /**
1336 * Sends to the Java side
1337 *
1338 * @param message The message to send.
1339 * @param returns whether the message was consumable (always true)
1340 */
1341
1342 bool
newMessageOnBus(const char * message)1343 JavaMessageSender::newMessageOnBus(const char* message)
1344 {
1345 char* msg = (char*) malloc(sizeof(char)*strlen(message) + 1);
1346 strcpy(msg, message);
1347 plugin_send_message_to_appletviewer(msg);
1348
1349 free(msg);
1350 msg = NULL;
1351
1352 // Always successful
1353 return true;
1354 }
1355
1356 /***********************************
1357 * Begin MessageBus implementation *
1358 ***********************************/
1359
1360 /**
1361 * Constructor.
1362 *
1363 * Initializes the mutexes needed by the other functions.
1364 */
MessageBus()1365 MessageBus::MessageBus()
1366 {
1367 int ret;
1368
1369 ret = pthread_mutex_init(&subscriber_mutex, NULL);
1370
1371 if(ret)
1372 PLUGIN_DEBUG("Error: Unable to initialize subscriber mutex: %d\n", ret);
1373
1374 ret = pthread_mutex_init(&msg_queue_mutex, NULL);
1375 if(ret)
1376 PLUGIN_DEBUG("Error: Unable to initialize message queue mutex: %d\n", ret);
1377
1378 PLUGIN_DEBUG("Mutexes %p and %p initialized\n", &subscriber_mutex, &msg_queue_mutex);
1379 }
1380
1381 /**
1382 * Destructor.
1383 *
1384 * Destroy the mutexes initialized by the constructor.
1385 */
1386
~MessageBus()1387 MessageBus::~MessageBus()
1388 {
1389 PLUGIN_DEBUG("MessageBus::~MessageBus\n");
1390
1391 int ret;
1392
1393 ret = pthread_mutex_destroy(&subscriber_mutex);
1394 if(ret)
1395 PLUGIN_DEBUG("Error: Unable to destroy subscriber mutex: %d\n", ret);
1396
1397 ret = pthread_mutex_destroy(&msg_queue_mutex);
1398 if(ret)
1399 PLUGIN_DEBUG("Error: Unable to destroy message queue mutex: %d\n", ret);
1400 }
1401
1402 /**
1403 * Adds the given BusSubscriber as a subscriber to self
1404 *
1405 * @param b The BusSubscriber to subscribe
1406 */
1407 void
subscribe(BusSubscriber * b)1408 MessageBus::subscribe(BusSubscriber* b)
1409 {
1410 // Applets may initialize in parallel. So lock before pushing.
1411
1412 PLUGIN_DEBUG("Subscribing %p to bus %p\n", b, this);
1413 pthread_mutex_lock(&subscriber_mutex);
1414 subscribers.push_back(b);
1415 pthread_mutex_unlock(&subscriber_mutex);
1416 }
1417
1418 /**
1419 * Removes the given BusSubscriber from the subscriber list
1420 *
1421 * @param b The BusSubscriber to ubsubscribe
1422 */
1423 void
unSubscribe(BusSubscriber * b)1424 MessageBus::unSubscribe(BusSubscriber* b)
1425 {
1426 // Applets may initialize in parallel. So lock before pushing.
1427
1428 PLUGIN_DEBUG("Un-subscribing %p from bus %p\n", b, this);
1429 pthread_mutex_lock(&subscriber_mutex);
1430 subscribers.remove(b);
1431 pthread_mutex_unlock(&subscriber_mutex);
1432 }
1433
1434 /**
1435 * Notifies all subscribers with the given message
1436 *
1437 * @param message The message to send to the subscribers
1438 */
1439 void
post(const char * message)1440 MessageBus::post(const char* message)
1441 {
1442 bool message_consumed = false;
1443
1444 PLUGIN_DEBUG("Trying to lock %p...\n", &msg_queue_mutex);
1445 pthread_mutex_lock(&subscriber_mutex);
1446
1447 PLUGIN_DEBUG("Message %s received on bus. Notifying subscribers.\n", message);
1448
1449 std::list<BusSubscriber*>::const_iterator i;
1450 for( i = subscribers.begin(); i != subscribers.end() && !message_consumed; ++i ) {
1451 PLUGIN_DEBUG("Notifying subscriber %p of %s\n", *i, message);
1452 message_consumed = ((BusSubscriber*) *i)->newMessageOnBus(message);
1453 }
1454
1455 pthread_mutex_unlock(&subscriber_mutex);
1456
1457 if (!message_consumed)
1458 PLUGIN_DEBUG("Warning: No consumer found for message %s\n", message);
1459
1460 PLUGIN_DEBUG("%p unlocked...\n", &msg_queue_mutex);
1461 }
1462
1463