The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "ppport.h"

#include <nsCOMPtr.h>
#include <nsIConsoleService.h>
#include <nsIConsoleListener.h>
#include <nsIConsoleMessage.h>
#include <nsIScriptError.h>
#include <nsIServiceManager.h>
#include <nsEmbedString.h>
#include <nsServiceManagerUtils.h>
#include "build/version.h"

#if MCS_MOZEMBED_VERSION < 1900
#define GetMessageMoz GetMessage
#endif /* MCS_MOZEMBED_VERSION */

static SV *wrap_unichar_string(const PRUnichar *uni_str) {
	nsEmbedString utf8;
	nsEmbedCString u8c;
	const char * u8str;

	utf8 = uni_str;
	NS_UTF16ToCString(utf8, NS_CSTRING_ENCODING_UTF8, u8c);

	u8str = u8c.get();
	return newSVpv(u8str, 0);
}

class MyListener : public nsIConsoleListener {
public:
	NS_DECL_ISUPPORTS
	NS_DECL_NSICONSOLELISTENER

	SV *callback_;
};

NS_IMPL_ISUPPORTS1(MyListener, nsIConsoleListener)

NS_IMETHODIMP MyListener::Observe(nsIConsoleMessage *msg) {
	dSP;
	PRUnichar *str;
	nsresult rv;
	const nsID id = NS_GET_IID(nsIScriptError);
	nsIScriptError *se = 0;
	SV *psv;
	nsEmbedCString u8c;

	msg->QueryInterface(id, (void **) &se);
	rv = se ? se->ToString(u8c) : msg->GetMessageMoz(&str);
	if (NS_FAILED(rv))
		goto out;

	if (u8c.get()) {
		psv = newSVpv(u8c.get(), 0);
	} else
		psv = wrap_unichar_string(str);


	ENTER;
	SAVETMPS;
	PUSHMARK(SP);
	XPUSHs(sv_2mortal(psv));
	PUTBACK;
	call_sv(this->callback_, G_DISCARD);
out:
	return rv;
}

MODULE = Mozilla::ConsoleService		PACKAGE = Mozilla::ConsoleService		

SV *Register(cb)
	SV *cb;
	INIT:
		nsresult rv;
		nsCOMPtr<nsIConsoleService> os;
		nsCOMPtr<MyListener> lis;
	CODE:
		rv = !NS_OK;
		lis = new MyListener;
		if (!lis)
			goto out_retval;

		os = do_GetService("@mozilla.org/consoleservice;1", &rv);
		if (NS_FAILED(rv))
			goto out_retval;

		rv = os->RegisterListener(lis);
		if (NS_FAILED(rv))
			goto out_retval;

		lis->callback_ = newSVsv(cb);
out_retval:
		RETVAL = (rv == NS_OK) ? newSViv((IV) lis.get()) : NULL;
	OUTPUT:
		RETVAL

void Unregister(SV *handle)
	INIT:
		nsresult rv;
		nsCOMPtr<nsIConsoleService> os;
	CODE:
		os = do_GetService("@mozilla.org/consoleservice;1", &rv);
		os->UnregisterListener((MyListener *) SvIV(handle));