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 (&current_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