Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar

This commit is contained in:
Simon McVittie 2007-05-24 12:26:28 +01:00
commit 677eb1629c
97 changed files with 4943 additions and 7509 deletions

View File

@ -1,6 +1,4 @@
SUBDIRS = bin browser data po shell sugar services
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = bin data lib po shell sugar services
bin_SCRIPTS = \
sugar-emulator

View File

@ -1,20 +1,6 @@
#!/bin/sh
# Run this to generate all the initial makefiles, etc.
export ACLOCAL="aclocal -I m4"
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
PKG_NAME="sugar"
(test -f $srcdir/README) || {
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
echo " top-level $PKG_NAME directory"
exit 1
}
which gnome-autogen.sh || {
echo "You need to install gnome-common from the GNOME CVS"
exit 1
}
REQUIRED_AUTOMAKE_VERSION=1.9 USE_GNOME2_MACROS=1 . gnome-autogen.sh
autoreconf -i
intltoolize
./configure "$@"

View File

@ -1,183 +0,0 @@
#include <config.h>
#include <stdio.h>
#include <gtkmozembed.h>
#include <gtkmozembed_internal.h>
#include <nsIRequest.h>
#include <nsNetUtil.h>
#include <nsISeekableStream.h>
#include <nsIHttpChannel.h>
#include <nsIUploadChannel.h>
#include <nsIWebBrowser.h>
#include <nsISHistory.h>
#include <nsIHistoryEntry.h>
#include <nsISHEntry.h>
#include <nsIInputStream.h>
#include <nsIWebNavigation.h>
#include "GeckoBrowserPersist.h"
GeckoBrowserPersist::GeckoBrowserPersist(SugarBrowser *browser)
: mBrowser(browser)
{
}
GeckoBrowserPersist::~GeckoBrowserPersist()
{
}
static nsresult
NewURI(const char *uri, nsIURI **result)
{
nsresult rv;
nsCOMPtr<nsIServiceManager> mgr;
NS_GetServiceManager (getter_AddRefs (mgr));
NS_ENSURE_TRUE(mgr, FALSE);
nsCOMPtr<nsIIOService> ioService;
rv = mgr->GetServiceByContractID ("@mozilla.org/network/io-service;1",
NS_GET_IID (nsIIOService),
getter_AddRefs(ioService));
NS_ENSURE_SUCCESS(rv, FALSE);
nsCString cSpec(uri);
return ioService->NewURI (cSpec, nsnull, nsnull, result);
}
static nsresult
GetPostData(SugarBrowser *browser, nsIInputStream **postData)
{
nsCOMPtr<nsIWebBrowser> webBrowser;
gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser),
getter_AddRefs(webBrowser));
NS_ENSURE_TRUE(webBrowser, NS_ERROR_FAILURE);
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(webBrowser));
NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
PRInt32 sindex;
nsCOMPtr<nsISHistory> sessionHistory;
webNav->GetSessionHistory(getter_AddRefs(sessionHistory));
NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE);
nsCOMPtr<nsIHistoryEntry> entry;
sessionHistory->GetIndex(&sindex);
sessionHistory->GetEntryAtIndex(sindex, PR_FALSE, getter_AddRefs(entry));
nsCOMPtr<nsISHEntry> shEntry(do_QueryInterface(entry));
if (shEntry) {
shEntry->GetPostData(postData);
}
return NS_OK;
}
bool
GeckoBrowserPersist::SaveURI(const char *uri, const char *filename)
{
nsresult rv;
nsCOMPtr<nsIURI> sourceURI;
rv = NewURI(uri, getter_AddRefs(sourceURI));
NS_ENSURE_SUCCESS(rv, FALSE);
nsCOMPtr<nsILocalFile> destFile = do_CreateInstance("@mozilla.org/file/local;1");
NS_ENSURE_TRUE(destFile, FALSE);
destFile->InitWithNativePath(nsCString(filename));
nsCOMPtr<nsIInputStream> postData;
GetPostData(mBrowser, getter_AddRefs(postData));
nsCOMPtr<nsIChannel> inputChannel;
rv = NS_NewChannel(getter_AddRefs(inputChannel), sourceURI,
nsnull, nsnull, nsnull, nsIRequest::LOAD_NORMAL);
NS_ENSURE_SUCCESS(rv, FALSE);
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(inputChannel));
if (httpChannel) {
nsCOMPtr<nsISeekableStream> stream(do_QueryInterface(postData));
if (stream)
{
// Rewind the postdata stream
stream->Seek(nsISeekableStream::NS_SEEK_SET, 0);
nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
// Attach the postdata to the http channel
uploadChannel->SetUploadStream(postData, EmptyCString(), -1);
}
}
nsCOMPtr<nsIInputStream> stream;
rv = inputChannel->Open(getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, FALSE);
nsCOMPtr<nsIFileOutputStream> fileOutputStream =
do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, FALSE);
rv = fileOutputStream->Init(destFile, -1, -1, 0);
NS_ENSURE_SUCCESS(rv, FALSE);
// Read data from the input and write to the output
char buffer[8192];
PRUint32 bytesRead;
PRUint32 bytesRemaining;
PRBool cancel = PR_FALSE;
PRBool readError;
rv = stream->Available(&bytesRemaining);
NS_ENSURE_SUCCESS(rv, FALSE);
while (!cancel && bytesRemaining)
{
readError = PR_TRUE;
rv = stream->Read(buffer, PR_MIN(sizeof(buffer), bytesRemaining), &bytesRead);
if (NS_SUCCEEDED(rv))
{
readError = PR_FALSE;
// Write out the data until something goes wrong, or, it is
// all written. We loop because for some errors (e.g., disk
// full), we get NS_OK with some bytes written, then an error.
// So, we want to write again in that case to get the actual
// error code.
const char *bufPtr = buffer; // Where to write from.
while (NS_SUCCEEDED(rv) && bytesRead)
{
PRUint32 bytesWritten = 0;
rv = fileOutputStream->Write(bufPtr, bytesRead, &bytesWritten);
if (NS_SUCCEEDED(rv))
{
bytesRead -= bytesWritten;
bufPtr += bytesWritten;
bytesRemaining -= bytesWritten;
// Force an error if (for some reason) we get NS_OK but
// no bytes written.
if (!bytesWritten)
{
rv = NS_ERROR_FAILURE;
cancel = PR_TRUE;
}
}
else
{
// Disaster - can't write out the bytes - disk full / permission?
cancel = PR_TRUE;
}
}
}
else
{
// Disaster - can't read the bytes - broken link / file error?
cancel = PR_TRUE;
}
}
NS_ENSURE_SUCCESS(rv, FALSE);
stream->Close();
return TRUE;
}

View File

@ -1,19 +0,0 @@
#ifndef __GECKO_BROWSER_PERSIST_H__
#define __GECKO_BROWSER_PERSIST_H__
#include "sugar-browser.h"
class GeckoBrowserPersist
{
public:
GeckoBrowserPersist(SugarBrowser *browser);
~GeckoBrowserPersist();
bool SaveURI(const char *uri, const char *filename);
private:
SugarBrowser *mBrowser;
protected:
/* additional members */
};
#endif // __GECKO_BROWSER_PERSIST_H__

View File

@ -1,142 +0,0 @@
#include <nsCExternalHandlerService.h>
#include <nsIFile.h>
#include <nsIFactory.h>
#include <nsILocalFile.h>
#include <nsStringAPI.h>
#include <nsComponentManagerUtils.h>
#include "GeckoContentHandler.h"
class GeckoContentHandler : public nsIHelperAppLauncherDialog
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIHELPERAPPLAUNCHERDIALOG
GeckoContentHandler();
virtual ~GeckoContentHandler();
};
GeckoContentHandler::GeckoContentHandler()
{
}
GeckoContentHandler::~GeckoContentHandler()
{
}
NS_IMPL_ISUPPORTS1(GeckoContentHandler, nsIHelperAppLauncherDialog)
NS_IMETHODIMP
GeckoContentHandler::Show (nsIHelperAppLauncher *aLauncher,
nsISupports *aContext,
PRUint32 aReason)
{
aLauncher->SaveToDisk(NULL, PR_FALSE);
return NS_OK;
}
#include <glib.h>
NS_IMETHODIMP
GeckoContentHandler::PromptForSaveToFile (nsIHelperAppLauncher *aLauncher,
nsISupports *aWindowContext,
const PRUnichar *aDefaultFile,
const PRUnichar *aSuggestedFileExtension,
nsILocalFile **_retval)
{
char *filename = NULL;
nsCString defaultFile;
NS_UTF16ToCString(nsString(aDefaultFile), NS_CSTRING_ENCODING_UTF8, defaultFile);
nsCOMPtr <nsILocalFile> destFile(do_CreateInstance("@mozilla.org/file/local;1"));
NS_ENSURE_TRUE(destFile, NS_ERROR_FAILURE);
const char * suggested = defaultFile.get();
if (strlen(suggested) > 0) {
filename = g_build_path("/", g_get_tmp_dir (), suggested, NULL);
} else {
filename = tempnam(NULL, NULL);
}
if (filename == NULL)
return NS_ERROR_OUT_OF_MEMORY;
destFile->InitWithNativePath(nsCString(filename));
g_free(filename);
NS_IF_ADDREF(*_retval = destFile);
return NS_OK;
}
//*****************************************************************************
// GeckoContentHandlerFactory
//*****************************************************************************
class GeckoContentHandlerFactory : public nsIFactory {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIFACTORY
GeckoContentHandlerFactory();
virtual ~GeckoContentHandlerFactory();
};
//*****************************************************************************
NS_IMPL_ISUPPORTS1(GeckoContentHandlerFactory, nsIFactory)
GeckoContentHandlerFactory::GeckoContentHandlerFactory() {
}
GeckoContentHandlerFactory::~GeckoContentHandlerFactory() {
}
NS_IMETHODIMP
GeckoContentHandlerFactory::CreateInstance(nsISupports *aOuter,
const nsIID & aIID,
void **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = NULL;
GeckoContentHandler *inst = new GeckoContentHandler;
if (!inst)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = inst->QueryInterface(aIID, aResult);
if (rv != NS_OK) {
// We didn't get the right interface, so clean up
delete inst;
}
return rv;
}
NS_IMETHODIMP
GeckoContentHandlerFactory::LockFactory(PRBool lock)
{
return NS_OK;
}
//*****************************************************************************
nsresult
NS_NewGeckoContentHandlerFactory(nsIFactory** aFactory)
{
NS_ENSURE_ARG_POINTER(aFactory);
*aFactory = nsnull;
GeckoContentHandlerFactory *result = new GeckoContentHandlerFactory;
if (!result)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(result);
*aFactory = result;
return NS_OK;
}

View File

@ -1,19 +0,0 @@
#ifndef __GECKO_CONTENT_HANDLER_H__
#define __GECKO_CONTENT_HANDLER_H__
#include <nsCOMPtr.h>
#include <nsIHelperAppLauncherDialog.h>
#define GECKOCONTENTHANDLER_CID \
{ /* 2321843e-6377-11db-967b-00e08161165f */ \
0x2321843e, \
0x6377, \
0x11db, \
{0x96, 0x7b, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f} \
}
class nsIFactory;
extern "C" NS_EXPORT nsresult NS_NewGeckoContentHandlerFactory(nsIFactory** aFactory);
#endif /* __GECKO_CONTENT_HANDLER_H */

View File

@ -1,86 +0,0 @@
#include "GeckoDirectoryProvider.h"
#include <nsCOMPtr.h>
#include <nsIIOService.h>
#include <nsNetUtil.h>
#include <nsArrayEnumerator.h>
#include <nsILocalFile.h>
#include <nsDirectoryServiceDefs.h>
#include <nsIToolkitChromeRegistry.h>
#include <nsIDirectoryService.h>
#include <nsCOMArray.h>
#include <glib.h>
NS_IMPL_ISUPPORTS2 (GeckoDirectoryProvider,
nsIDirectoryServiceProvider,
nsIDirectoryServiceProvider2)
GeckoDirectoryProvider::GeckoDirectoryProvider(const char *sugar_path,
const char *profile_path)
{
mComponentPath = g_build_filename
(sugar_path, "mozilla", "components", NULL);
mCompregPath = g_build_filename
(profile_path, "compreg.dat", NULL);
}
GeckoDirectoryProvider::~GeckoDirectoryProvider()
{
if(mComponentPath)
g_free(mComponentPath);
if(mCompregPath)
g_free(mCompregPath);
}
/* nsIFile getFile (in string prop, out PRBool persistent); */
NS_IMETHODIMP
GeckoDirectoryProvider::GetFile (const char *prop,
PRBool *persistent,
nsIFile **_retval)
{
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsILocalFile> file;
if (!strcmp(prop, NS_XPCOM_COMPONENT_REGISTRY_FILE)) {
rv = NS_NewNativeLocalFile(nsDependentCString(mCompregPath),
PR_TRUE,
getter_AddRefs(file));
}
if (NS_SUCCEEDED(rv) && file) {
NS_ADDREF(*_retval = file);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
/* nsISimpleEnumerator getFiles (in string aProperty); */
NS_IMETHODIMP
GeckoDirectoryProvider::GetFiles (const char *aProperty, nsISimpleEnumerator **aResult)
{
nsresult rv = NS_ERROR_FAILURE;
if (!strcmp(aProperty, NS_XPCOM_COMPONENT_DIR_LIST)) {
if (mComponentPath) {
nsCOMPtr<nsILocalFile> componentDir;
rv = NS_NewNativeLocalFile(nsDependentCString(mComponentPath),
PR_TRUE,
getter_AddRefs(componentDir));
NS_ENSURE_SUCCESS (rv, rv);
nsCOMArray<nsIFile> array;
rv = array.AppendObject (componentDir);
NS_ENSURE_SUCCESS (rv, rv);
rv = NS_NewArrayEnumerator (aResult, array);
NS_ENSURE_SUCCESS (rv, rv);
rv = NS_SUCCESS_AGGREGATE_RESULT;
}
}
return rv;
}

View File

@ -1,40 +0,0 @@
/*
* Copyright (C) 2007, One Laptop Per Child
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef GECKO_DIRECTORY_PROVIDER_H
#define GECKO_DIRECTORY_PROVIDER_H
#include <nsIDirectoryService.h>
class GeckoDirectoryProvider : public nsIDirectoryServiceProvider2
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDIRECTORYSERVICEPROVIDER
NS_DECL_NSIDIRECTORYSERVICEPROVIDER2
GeckoDirectoryProvider(const char *sugar_path,
const char *profile_path);
virtual ~GeckoDirectoryProvider();
private:
char *mComponentPath;
char *mCompregPath;
};
#endif /* GECKO_DIRECTORY_PROVIDER_H */

View File

@ -1,237 +0,0 @@
#include <config.h>
#include <unistd.h>
#include <glib.h>
#include <imgICache.h>
#include <nsComponentManagerUtils.h>
#include <nsCOMPtr.h>
#include <nsIDOMHTMLElement.h>
#include <nsIInterfaceRequestorUtils.h>
#include <nsIIOService.h>
#include <nsILocalFile.h>
#include <nsIMIMEHeaderParam.h>
#include <nsIProperties.h>
#include <nsISupportsPrimitives.h>
#include <nsIURI.h>
#include <nsIURL.h>
#include <nsServiceManagerUtils.h>
#include <nsStringAPI.h>
#include "GeckoDocumentObject.h"
#include "GeckoBrowserPersist.h"
GeckoDocumentObject::GeckoDocumentObject(SugarBrowser *browser, nsIDOMNode *node)
: mBrowser(browser),
mNode(node),
mImage(NULL)
{
}
GeckoDocumentObject::~GeckoDocumentObject()
{
}
bool GeckoDocumentObject::IsImage()
{
if(mImage) {
return true;
}
nsresult rv;
PRUint16 type;
rv = mNode->GetNodeType(&type);
if(NS_FAILED(rv)) return rv;
nsCOMPtr<nsIDOMHTMLElement> element = do_QueryInterface(mNode);
if ((nsIDOMNode::ELEMENT_NODE == type) && element) {
nsString uTag;
rv = element->GetLocalName(uTag);
if(NS_FAILED(rv)) return rv;
nsCString tag;
NS_UTF16ToCString (uTag, NS_CSTRING_ENCODING_UTF8, tag);
if (g_ascii_strcasecmp (tag.get(), "img") == 0) {
nsCOMPtr <nsIDOMHTMLImageElement> imagePtr;
imagePtr = do_QueryInterface(mNode, &rv);
if(NS_FAILED(rv)) return rv;
mImage = imagePtr;
return true;
}
}
return false;
}
static nsresult
NewURI(const char *uri, nsIURI **result)
{
nsresult rv;
nsCOMPtr<nsIServiceManager> mgr;
NS_GetServiceManager (getter_AddRefs (mgr));
NS_ENSURE_TRUE(mgr, FALSE);
nsCOMPtr<nsIIOService> ioService;
rv = mgr->GetServiceByContractID ("@mozilla.org/network/io-service;1",
NS_GET_IID (nsIIOService),
getter_AddRefs(ioService));
NS_ENSURE_SUCCESS(rv, FALSE);
nsCString cSpec(uri);
return ioService->NewURI (cSpec, nsnull, nsnull, result);
}
static nsresult
FilenameFromContentDisposition(nsCString contentDisposition, nsCString &fileName)
{
nsresult rv;
nsCString fallbackCharset;
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
do_GetService("@mozilla.org/network/mime-hdrparam;1");
NS_ENSURE_TRUE(mimehdrpar, NS_ERROR_FAILURE);
nsString aFileName;
rv = mimehdrpar->GetParameter (contentDisposition, "filename",
fallbackCharset, PR_TRUE, nsnull,
aFileName);
if (NS_FAILED(rv) || !fileName.Length()) {
rv = mimehdrpar->GetParameter (contentDisposition, "name",
fallbackCharset, PR_TRUE, nsnull,
aFileName);
}
if (NS_SUCCEEDED(rv) && fileName.Length()) {
NS_UTF16ToCString (aFileName, NS_CSTRING_ENCODING_UTF8, fileName);
}
return NS_OK;
}
static nsresult
GetImageProperties(char *imgURIStr, nsIProperties **properties)
{
nsresult rv;
nsCOMPtr<nsIURI> imageURI;
rv = NewURI(imgURIStr, getter_AddRefs(imageURI));
if(NS_FAILED(rv)) return rv;
nsCOMPtr<nsIServiceManager> mgr;
NS_GetServiceManager(getter_AddRefs(mgr));
NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE);
nsCOMPtr<imgICache> imgCache;
rv = mgr->GetServiceByContractID("@mozilla.org/image/cache;1",
NS_GET_IID(imgICache),
getter_AddRefs(imgCache));
if(NS_FAILED(rv)) return rv;
imgCache->FindEntryProperties(imageURI, properties);
NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE);
return NS_OK;
}
char *
GeckoDocumentObject::GetImageName()
{
if(!IsImage()) {
return NULL;
}
if(mImageName.Length()) {
return g_strdup(mImageName.get());
}
nsresult rv;
char *imgURIStr = GetImageURI();
nsCOMPtr<nsIProperties> imgProperties;
rv = GetImageProperties(imgURIStr, getter_AddRefs(imgProperties));
NS_ENSURE_SUCCESS(rv, NULL);
if (imgProperties) {
nsCOMPtr<nsISupportsCString> dispositionCString;
imgProperties->Get("content-disposition",
NS_GET_IID(nsISupportsCString),
getter_AddRefs(dispositionCString));
if (dispositionCString) {
nsCString contentDisposition;
dispositionCString->GetData(contentDisposition);
FilenameFromContentDisposition(contentDisposition, mImageName);
}
}
if (!mImageName.Length()) {
nsCOMPtr<nsIURI> imageURI;
rv = NewURI(imgURIStr, getter_AddRefs(imageURI));
NS_ENSURE_SUCCESS(rv, NULL);
nsCOMPtr<nsIURL> url(do_QueryInterface(imageURI));
if (url) {
url->GetFileName(mImageName);
}
}
return mImageName.Length() ? g_strdup(mImageName.get()) : NULL;
}
char *
GeckoDocumentObject::GetImageMimeType()
{
if(!IsImage()) {
return NULL;
}
if(mImageMimeType.Length()) {
return g_strdup(mImageMimeType.get());
}
nsresult rv;
char *imgURIStr = GetImageURI();
nsCOMPtr<nsIProperties> imgProperties;
rv = GetImageProperties(imgURIStr, getter_AddRefs(imgProperties));
NS_ENSURE_SUCCESS(rv, NULL);
if (imgProperties) {
nsCOMPtr<nsISupportsCString> typeCString;
imgProperties->Get("type",
NS_GET_IID(nsISupportsCString),
getter_AddRefs(typeCString));
if (typeCString) {
typeCString->GetData(mImageMimeType);
}
}
return mImageMimeType.Length() ? g_strdup(mImageMimeType.get()) : NULL;
}
char *
GeckoDocumentObject::GetImageURI()
{
if(!IsImage()) {
return NULL;
}
if(!mImageURI.Length()) {
nsresult rv;
nsString img;
rv = mImage->GetSrc(img);
if (NS_FAILED(rv)) return NULL;
NS_UTF16ToCString (img, NS_CSTRING_ENCODING_UTF8, mImageURI);
}
return g_strdup(mImageURI.get());
}
bool
GeckoDocumentObject::SaveImage(const char *filename)
{
GeckoBrowserPersist browserPersist(mBrowser);
return browserPersist.SaveURI(mImageURI.get(), filename);
}

View File

@ -1,31 +0,0 @@
#ifndef __GECKO_DOCUMENT_OBJECT_H__
#define __GECKO_DOCUMENT_OBJECT_H__
#include <nsIDOMNode.h>
#include <nsIDOMHTMLImageElement.h>
#include "sugar-browser.h"
class GeckoDocumentObject
{
public:
GeckoDocumentObject(SugarBrowser *browser, nsIDOMNode *node);
~GeckoDocumentObject();
bool IsImage();
char *GetImageURI();
char *GetImageName();
char *GetImageMimeType();
bool SaveImage(const char *filename);
private:
SugarBrowser *mBrowser;
nsCOMPtr<nsIDOMNode> mNode;
nsCOMPtr<nsIDOMHTMLImageElement> mImage;
nsCString mImageURI;
nsCString mImageName;
nsCString mImageMimeType;
protected:
/* additional members */
};
#endif // __GECKO_DOCUMENT_OBJECT_H__

View File

@ -1,262 +0,0 @@
#include "config.h"
#include <nsIFactory.h>
#include <nsIFile.h>
#include <nsIFileURL.h>
#include <nsServiceManagerUtils.h>
#include <nsIMIMEService.h>
#include "sugar-download-manager.h"
#include "GeckoDownload.h"
#define APPLICATION_OCTET_STREAM "application/octet-stream"
class GeckoDownload : public nsITransfer
{
public:
GeckoDownload();
virtual ~GeckoDownload();
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
NS_DECL_NSIWEBPROGRESSLISTENER2
NS_DECL_NSITRANSFER
protected:
nsIURI *mSource;
nsCString mTargetFileName;
nsIMIMEInfo *mMIMEInfo;
nsILocalFile *mTempFile;
};
GeckoDownload::GeckoDownload ()
{
}
GeckoDownload::~GeckoDownload ()
{
}
NS_IMPL_ISUPPORTS3 (GeckoDownload,
nsIWebProgressListener,
nsIWebProgressListener2,
nsITransfer)
NS_IMETHODIMP
GeckoDownload::Init (nsIURI *aSource,
nsIURI *aTarget,
const nsAString &aDisplayName,
nsIMIMEInfo *aMIMEInfo,
PRTime aStartTime,
nsILocalFile *aTempFile,
nsICancelable *aCancelable)
{
mSource = aSource;
mMIMEInfo = aMIMEInfo;
mTempFile = aTempFile;
nsresult rv;
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aTarget);
NS_ENSURE_TRUE(fileURL, NS_ERROR_FAILURE);
nsCOMPtr<nsIFile> file;
rv = fileURL->GetFile(getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
file->GetNativePath (mTargetFileName);
return NS_OK;
}
NS_IMETHODIMP
GeckoDownload::OnStateChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRUint32 aStateFlags,
nsresult aStatus)
{
SugarDownloadManager *download_manager = sugar_get_download_manager();
if(aStateFlags == STATE_START) {
nsCString url;
nsCString mimeType;
mMIMEInfo->GetMIMEType(mimeType);
mSource->GetSpec(url);
/* If the file is application/octet-stream, look up a better mime type
from the extension. */
if(mimeType.Equals(APPLICATION_OCTET_STREAM)) {
nsresult rv;
nsCOMPtr<nsIMIMEService> mimeService(
do_GetService("@mozilla.org/mime;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
const char *fileExt = strrchr(mTargetFileName.get(), '.');
if(fileExt) {
nsCString contentType;
mimeService->GetTypeFromExtension(nsCString(fileExt),
contentType);
if(!contentType.IsEmpty()) {
mimeType = contentType;
}
}
}
sugar_download_manager_download_started(download_manager,
url.get(),
mimeType.get(),
mTargetFileName.get());
} else if(aStateFlags == STATE_STOP) {
if(NS_SUCCEEDED(aStatus)) {
sugar_download_manager_download_completed(download_manager,
mTargetFileName.get());
} else {
sugar_download_manager_download_cancelled(download_manager,
mTargetFileName.get());
}
}
return NS_OK;
}
NS_IMETHODIMP
GeckoDownload::OnProgressChange (nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
return OnProgressChange64 (aWebProgress,
aRequest,
aCurSelfProgress,
aMaxSelfProgress,
aCurTotalProgress,
aMaxTotalProgress);
}
NS_IMETHODIMP
GeckoDownload::OnProgressChange64 (nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt64 aCurSelfProgress,
PRInt64 aMaxSelfProgress,
PRInt64 aCurTotalProgress,
PRInt64 aMaxTotalProgress)
{
SugarDownloadManager *download_manager = sugar_get_download_manager ();
PRInt32 percentComplete =
(PRInt32)(((float)aCurSelfProgress / (float)aMaxSelfProgress) * 100.0);
sugar_download_manager_update_progress (download_manager,
mTargetFileName.get (),
percentComplete);
return NS_OK;
}
NS_IMETHODIMP
GeckoDownload::OnLocationChange (nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
nsIURI *location)
{
return NS_OK;
}
NS_IMETHODIMP
GeckoDownload::OnStatusChange (nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
nsresult aStatus,
const PRUnichar *aMessage)
{
return NS_OK;
}
NS_IMETHODIMP
GeckoDownload::OnSecurityChange (nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRUint32 state)
{
return NS_OK;
}
NS_IMETHODIMP
GeckoDownload::OnRefreshAttempted (nsIWebProgress *aWebProgress,
nsIURI *aRefreshURI,
PRInt32 aMillis,
PRBool aSameURI,
PRBool *_retval)
{
return NS_OK;
}
//*****************************************************************************
// GeckoDownloadFactory
//*****************************************************************************
class GeckoDownloadFactory : public nsIFactory {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIFACTORY
GeckoDownloadFactory();
virtual ~GeckoDownloadFactory();
};
//*****************************************************************************
NS_IMPL_ISUPPORTS1(GeckoDownloadFactory, nsIFactory)
GeckoDownloadFactory::GeckoDownloadFactory() {
}
GeckoDownloadFactory::~GeckoDownloadFactory() {
}
NS_IMETHODIMP
GeckoDownloadFactory::CreateInstance(nsISupports *aOuter, const nsIID & aIID, void **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = NULL;
GeckoDownload *inst = new GeckoDownload;
if (!inst)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = inst->QueryInterface(aIID, aResult);
if (rv != NS_OK) {
// We didn't get the right interface, so clean up
delete inst;
}
return rv;
}
NS_IMETHODIMP
GeckoDownloadFactory::LockFactory(PRBool lock)
{
return NS_OK;
}
//*****************************************************************************
nsresult
NS_NewGeckoDownloadFactory(nsIFactory** aFactory)
{
NS_ENSURE_ARG_POINTER(aFactory);
*aFactory = nsnull;
GeckoDownloadFactory *result = new GeckoDownloadFactory;
if (!result)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(result);
*aFactory = result;
return NS_OK;
}

View File

@ -1,25 +0,0 @@
#ifndef __GECKO_DOWNLOAD_H__
#define __GECKO_DOWNLOAD_H__
#include <nsCOMPtr.h>
#include <nsIInterfaceRequestor.h>
#include <nsITransfer.h>
#include <nsIWebProgressListener.h>
#include <nsIMIMEInfo.h>
#include <nsIURL.h>
#include <nsILocalFile.h>
#include <nsStringAPI.h>
#define GECKODOWNLOAD_CID \
{ /* b1813bbe-6518-11db-967e-00e08161165f */ \
0xb1813bbe, \
0x6518, \
0x11db, \
{0x96, 0x7e, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f} \
}
class nsIFactory;
extern "C" NS_EXPORT nsresult NS_NewGeckoDownloadFactory(nsIFactory** aFactory);
#endif // __GECKO_DOWNLOAD_H__

View File

@ -1,214 +0,0 @@
#include <config.h>
#include <sys/time.h>
#include <time.h>
#include <glib.h>
#include <nsStringAPI.h>
#include <nsCOMPtr.h>
#include <nsITransferable.h>
#include <nsISupportsPrimitives.h>
#include <nsIDOMEventTarget.h>
#include <nsComponentManagerUtils.h>
#include <nsServiceManagerUtils.h>
#include <nsIInterfaceRequestorUtils.h>
#include <nsIDOMMouseEvent.h>
#include <nsIMIMEService.h>
#include "GeckoDragDropHooks.h"
#include "GeckoDocumentObject.h"
#define TEXT_URI_LIST "text/uri-list"
#define TEXT_X_MOZ_URL "text/x-moz-url"
#define FILE_LOCALHOST "file://"
//*****************************************************************************
// UriListDataProvider
//*****************************************************************************
class UriListDataProvider : public nsIFlavorDataProvider
{
public:
UriListDataProvider(GeckoDocumentObject *mDocumentObject);
virtual ~UriListDataProvider();
NS_DECL_ISUPPORTS
NS_DECL_NSIFLAVORDATAPROVIDER
private:
GeckoDocumentObject *mDocumentObject;
nsCString mFilePath;
};
//*****************************************************************************
NS_IMPL_ISUPPORTS1(UriListDataProvider, nsIFlavorDataProvider)
UriListDataProvider::UriListDataProvider(GeckoDocumentObject *documentObject)
: mDocumentObject(documentObject)
{
}
UriListDataProvider::~UriListDataProvider()
{
if(mFilePath.Length()) {
remove(mFilePath.get());
}
delete mDocumentObject;
}
NS_IMETHODIMP
UriListDataProvider::GetFlavorData(nsITransferable *aTransferable,
const char *aFlavor, nsISupports **aData,
PRUint32 *aDataLen)
{
NS_ENSURE_ARG_POINTER(aData && aDataLen);
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
char *image_name;
char *mime_type;
char *file_ext;
nsCString mime_ext;
timeval timestamp;
*aData = nsnull;
*aDataLen = 0;
if(g_ascii_strcasecmp(aFlavor, TEXT_URI_LIST) != 0) {
return rv;
}
gettimeofday(&timestamp, NULL);
mFilePath.Append(g_get_tmp_dir());
mFilePath.Append("/");
mFilePath.AppendInt(timestamp.tv_sec);
mFilePath.AppendInt(timestamp.tv_usec);
image_name = mDocumentObject->GetImageName();
file_ext = strrchr(image_name, '.');
mime_type = mDocumentObject->GetImageMimeType();
nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1",
&rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = mimeService->GetPrimaryExtension(nsCString(mime_type),
EmptyCString(),
mime_ext);
NS_ENSURE_SUCCESS(rv, rv);
if(!file_ext) {
mFilePath.Append(image_name);
mFilePath.Append(".");
mFilePath.Append(mime_ext);
} else if(strcmp(file_ext, mime_ext.get())) {
image_name[strlen(file_ext)] = 0;
mFilePath.Append(image_name);
mFilePath.Append(".");
mFilePath.Append(mime_ext);
} else {
mFilePath.Append(image_name);
}
g_free(mime_type);
g_free(image_name);
if(!mDocumentObject->SaveImage(mFilePath.get())) {
return NS_ERROR_FAILURE;
}
nsCString localURI(FILE_LOCALHOST);
localURI.Append(mFilePath);
nsString localURI16;
NS_CStringToUTF16(localURI, NS_CSTRING_ENCODING_UTF8, localURI16);
nsCOMPtr<nsISupportsString> localURIData(do_CreateInstance(
"@mozilla.org/supports-string;1", &rv));
if(NS_FAILED(rv)) return rv;
rv = localURIData->SetData(localURI16);
if(NS_FAILED(rv)) return rv;
CallQueryInterface(localURIData, aData);
*aDataLen = sizeof(nsISupportsString*);
// FIXME: Why do we need this? Is there a leak in mozilla?
this->Release();
return rv;
}
//*****************************************************************************
// GeckoDragDropHooks
//*****************************************************************************
NS_IMPL_ISUPPORTS1(GeckoDragDropHooks, nsIClipboardDragDropHooks)
GeckoDragDropHooks::GeckoDragDropHooks(SugarBrowser *browser)
: mBrowser(browser)
{
}
GeckoDragDropHooks::~GeckoDragDropHooks()
{
}
NS_IMETHODIMP
GeckoDragDropHooks::AllowStartDrag(nsIDOMEvent *event, PRBool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
GeckoDragDropHooks::AllowDrop(nsIDOMEvent *event, nsIDragSession *session,
PRBool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
GeckoDragDropHooks::OnCopyOrDrag(nsIDOMEvent *aEvent, nsITransferable *trans,
PRBool *_retval)
{
nsresult rv;
*_retval = true;
nsCOMPtr<nsIDOMMouseEvent> mouseEvent;
mouseEvent = do_QueryInterface(aEvent, &rv);
if(NS_FAILED(rv)) return rv;
nsCOMPtr<nsIDOMEventTarget> eventTarget;
rv = mouseEvent->GetTarget(getter_AddRefs(eventTarget));
if(NS_FAILED(rv)) return rv;
nsCOMPtr<nsIDOMNode> targetNode;
targetNode = do_QueryInterface(eventTarget, &rv);
if(NS_FAILED(rv)) return rv;
GeckoDocumentObject *documentObject = new GeckoDocumentObject(mBrowser,
targetNode);
if(documentObject->IsImage()) {
rv = trans->RemoveDataFlavor(TEXT_X_MOZ_URL);
if(NS_FAILED(rv)) return rv;
rv = trans->AddDataFlavor(TEXT_URI_LIST);
if(NS_FAILED(rv)) return rv;
UriListDataProvider *rawPtr = new UriListDataProvider(documentObject);
nsCOMPtr<nsISupports> dataProvider(do_QueryInterface(rawPtr, &rv));
if(NS_FAILED(rv)) return rv;
rv = trans->SetTransferData(TEXT_URI_LIST, dataProvider, 0);
if(NS_FAILED(rv)) return rv;
}
return rv;
}
NS_IMETHODIMP
GeckoDragDropHooks::OnPasteOrDrop(nsIDOMEvent *event, nsITransferable *trans,
PRBool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -1,25 +0,0 @@
#ifndef __GECKO_DRAG_DROP_HOOKS_H__
#define __GECKO_DRAG_DROP_HOOKS_H__
#include <nsIClipboardDragDropHooks.h>
#include "sugar-browser.h"
class GeckoDragDropHooks : public nsIClipboardDragDropHooks
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICLIPBOARDDRAGDROPHOOKS
GeckoDragDropHooks(SugarBrowser *browser);
private:
~GeckoDragDropHooks();
SugarBrowser *mBrowser;
protected:
/* additional members */
};
#endif // __GECKO_DRAG_DROP_HOOKS_H__

View File

@ -1,83 +0,0 @@
SUBDIRS = components
libsugarbrowser_la_CPPFLAGS = \
$(WARN_CFLAGS) \
$(LIB_CFLAGS) \
$(GECKO_CFLAGS) \
$(NSPR_CFLAGS) \
-I$(MOZILLA_INCLUDE_DIR)/chrome \
-I$(MOZILLA_INCLUDE_DIR)/commandhandler \
-I$(MOZILLA_INCLUDE_DIR)/content \
-I$(MOZILLA_INCLUDE_DIR)/dom \
-I$(MOZILLA_INCLUDE_DIR)/docshell \
-I$(MOZILLA_INCLUDE_DIR)/exthandler \
-I$(MOZILLA_INCLUDE_DIR)/gtkembedmoz \
-I$(MOZILLA_INCLUDE_DIR)/imglib2 \
-I$(MOZILLA_INCLUDE_DIR)/mimetype \
-I$(MOZILLA_INCLUDE_DIR)/necko \
-I$(MOZILLA_INCLUDE_DIR)/pref \
-I$(MOZILLA_INCLUDE_DIR)/shistory \
-I$(MOZILLA_INCLUDE_DIR)/uriloader \
-I$(MOZILLA_INCLUDE_DIR)/webbrwsr \
-I$(MOZILLA_INCLUDE_DIR)/webbrowserpersist \
-I$(MOZILLA_INCLUDE_DIR)/widget \
-I$(MOZILLA_INCLUDE_DIR)/xpcom \
-I$(top_builddir)/browser/components/sessionstore \
-I$(top_builddir)/browser/components/browserhelper \
-DPLUGIN_DIR=\"$(libdir)/mozilla/plugins\" \
-DSHARE_DIR=\"$(pkgdatadir)\"
noinst_LTLIBRARIES = libsugarbrowser.la
libsugarbrowser_la_LIBADD = \
$(LIB_LIBS) \
$(GECKO_LIBS)
libsugarbrowser_la_SOURCES = \
$(BUILT_SOURCES) \
GeckoBrowserPersist.h \
GeckoBrowserPersist.cpp \
GeckoContentHandler.h \
GeckoContentHandler.cpp \
GeckoDocumentObject.h \
GeckoDocumentObject.cpp \
GeckoDirectoryProvider.h \
GeckoDirectoryProvider.cpp \
GeckoDragDropHooks.h \
GeckoDragDropHooks.cpp \
GeckoDownload.h \
GeckoDownload.cpp \
sugar-address-entry.c \
sugar-address-entry.h \
sugar-browser.h \
sugar-browser.cpp \
sugar-download.h \
sugar-download.c \
sugar-download-manager.h \
sugar-download-manager.c
BUILT_SOURCES = \
sugar-marshal.c \
sugar-marshal.h
stamp_files = \
stamp-sugar-marshal.c \
stamp-sugar-marshal.h
sugar-marshal.c: stamp-sugar-marshal.c
@true
stamp-sugar-marshal.c: sugar-marshal.list
$(GLIB_GENMARSHAL) --prefix=sugar_marshal $(srcdir)/sugar-marshal.list --header --body > sugar-marshal.c \
&& echo timestamp > $(@F)
sugar-marshal.h: stamp-sugar-marshal.h
@true
stamp-sugar-marshal.h: sugar-marshal.list
$(GLIB_GENMARSHAL) --prefix=sugar_marshal $(srcdir)/sugar-marshal.list --header > sugar-marshal.h \
&& echo timestamp > $(@F)
CLEANFILES = $(stamp_files) $(BUILT_SOURCES)
DISTCLEANFILES = $(stamp_files) $(BUILT_SOURCES)
MAINTAINERCLEANFILES = $(stamp_files) $(BUILT_SOURCES)
EXTRA_DIST = sugar-marshal.list

View File

@ -1 +0,0 @@
SUBDIRS = browserhelper sessionstore

View File

@ -1,4 +0,0 @@
nsIBrowserHelper.h
nsIBrowserHelper.xpt
stamp-nsIBrowserHelper.h
stamp-nsIBrowserHelper.xpt

View File

@ -1,32 +0,0 @@
sessionstoredir = $(pkgdatadir)/mozilla/components
sessionstore_DATA = \
nsIBrowserHelper.xpt \
nsBrowserHelper.js
BUILT_SOURCES = \
nsIBrowserHelper.xpt \
nsIBrowserHelper.h
stamp_files = \
stamp-nsIBrowserHelper.xpt \
stamp-nsIBrowserHelper.h
nsIBrowserHelper.xpt: stamp-nsIBrowserHelper.xpt
@true
stamp-nsIBrowserHelper.xpt: nsIBrowserHelper.idl
$(XPIDL) -m typelib -w -v -I $(MOZILLA_IDL_DIR) -e nsIBrowserHelper.xpt \
$(srcdir)/nsIBrowserHelper.idl \
&& echo timestamp > $(@F)
nsIBrowserHelper.h: stamp-nsIBrowserHelper.h
@true
stamp-nsIBrowserHelper.h: nsIBrowserHelper.idl
$(XPIDL) -m header -w -v -I $(MOZILLA_IDL_DIR) -e nsIBrowserHelper.h \
$(srcdir)/nsIBrowserHelper.idl \
&& echo timestamp > $(@F)
CLEANFILES = $(stamp_files) $(BUILT_SOURCES)
DISTCLEANFILES = $(stamp_files) $(BUILT_SOURCES)
MAINTAINERCLEANFILES = $(stamp_files) $(BUILT_SOURCES)
EXTRA_DIST = nsIBrowserHelper.idl nsBrowserHelper.js

View File

@ -1,100 +0,0 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const CID = Components.ID("{475e1194-92bc-4e03-92f3-5ad6ccddaca3}");
const CONTRACT_ID = "@laptop.org/browser/browserhelper;1";
const CLASS_NAME = "Browser Helper";
var browsers = [];
function BrowserHelperService() {
}
BrowserHelperService.prototype = {
/* ........ nsIBrowserHelper API .............. */
getBrowser: function bh_getBrowser(aId) {
return browsers[aId]
},
registerBrowser: function bh_registerBrowser(aId, aBrowser) {
browsers[aId] = aBrowser;
},
unregisterBrowser: function bh_unregisterBrowser(aId) {
browsers.pop(aId)
},
QueryInterface: function(aIID) {
if (!aIID.equals(Ci.nsISupports) &&
!aIID.equals(Ci.nsIBrowserHelper)) {
Components.returnCode = Cr.NS_ERROR_NO_INTERFACE;
return null;
}
return this;
}
}
/* :::::::: Service Registration & Initialization ::::::::::::::: */
/* ........ nsIModule .............. */
const BrowserHelperModule = {
getClassObject: function(aCompMgr, aCID, aIID) {
if (aCID.equals(CID)) {
return BrowserHelperFactory;
}
Components.returnCode = Cr.NS_ERROR_NOT_REGISTERED;
return null;
},
registerSelf: function(aCompMgr, aFileSpec, aLocation, aType) {
aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
aCompMgr.registerFactoryLocation(CID, CLASS_NAME, CONTRACT_ID, aFileSpec, aLocation, aType);
},
unregisterSelf: function(aCompMgr, aLocation, aType) {
aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
aCompMgr.unregisterFactoryLocation(CID, aLocation);
},
canUnload: function(aCompMgr) {
return true;
}
}
/* ........ nsIFactory .............. */
const BrowserHelperFactory = {
createInstance: function(aOuter, aIID) {
if (aOuter != null) {
Components.returnCode = Cr.NS_ERROR_NO_AGGREGATION;
return null;
}
return (new BrowserHelperService()).QueryInterface(aIID);
},
lockFactory: function(aLock) { },
QueryInterface: function(aIID) {
if (!aIID.equals(Ci.nsISupports) && !aIID.equals(Ci.nsIModule) &&
!aIID.equals(Ci.nsIFactory) && !aIID.equals(Ci.nsIBrowserHelper)) {
Components.returnCode = Cr.NS_ERROR_NO_INTERFACE;
return null;
}
return this;
}
};
function NSGetModule(aComMgr, aFileSpec) {
dump("nsBrowserHelper: NSGetModule\n")
return BrowserHelperModule;
}

View File

@ -1,13 +0,0 @@
#include "nsISupports.idl"
interface nsIWebBrowser;
[scriptable, uuid(475e1194-92bc-4e03-92f3-5ad6ccddaca3)]
interface nsIBrowserHelper : nsISupports
{
nsIWebBrowser getBrowser(in long id);
void registerBrowser(in long id, in nsIWebBrowser browser);
void unregisterBrowser(in long id);
};

View File

@ -1,4 +0,0 @@
nsISessionStore.h
nsISessionStore.xpt
stamp-nsISessionStore.h
stamp-nsISessionStore.xpt

View File

@ -1,32 +0,0 @@
sessionstoredir = $(pkgdatadir)/mozilla/components
sessionstore_DATA = \
nsISessionStore.xpt \
nsSessionStore.js
BUILT_SOURCES = \
nsISessionStore.xpt \
nsISessionStore.h
stamp_files = \
stamp-nsISessionStore.xpt \
stamp-nsISessionStore.h
nsISessionStore.xpt: stamp-nsISessionStore.xpt
@true
stamp-nsISessionStore.xpt: nsISessionStore.idl
$(XPIDL) -m typelib -w -v -I $(MOZILLA_IDL_DIR) -e nsISessionStore.xpt \
$(srcdir)/nsISessionStore.idl \
&& echo timestamp > $(@F)
nsISessionStore.h: stamp-nsISessionStore.h
@true
stamp-nsISessionStore.h: nsISessionStore.idl
$(XPIDL) -m header -w -v -I $(MOZILLA_IDL_DIR) -e nsISessionStore.h \
$(srcdir)/nsISessionStore.idl \
&& echo timestamp > $(@F)
CLEANFILES = $(stamp_files) $(BUILT_SOURCES)
DISTCLEANFILES = $(stamp_files) $(BUILT_SOURCES)
MAINTAINERCLEANFILES = $(stamp_files) $(BUILT_SOURCES)
EXTRA_DIST = nsISessionStore.idl nsSessionStore.js

View File

@ -1,63 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Session Restore component.
*
* The Initial Developer of the Original Code is
* Simon Bünzli <zeniko@gmail.com>
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dietrich Ayala <dietrich@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsIWebBrowser;
/**
* nsISessionStore keeps track of the current browsing state - i.e.
* tab history, cookies, scroll state, form data, POSTDATA and window features
* - and allows to restore everything into one window.
*/
[scriptable, uuid(11852a90-20de-11db-a98b-0800200c9a66)]
interface nsISessionStore : nsISupports
{
/**
* @param aBrowser is the browser whose state is to be returned.
*
* @return a JSON string representing the session state.
*/
AString getBrowserState(in nsIWebBrowser aBrowser);
/**
* @param aBrowser is the browser whose state is to be set.
* @param aState is a JSON string representing a session state.
*/
void setBrowserState(in nsIWebBrowser aBrowser, in AString aState);
};

View File

@ -1,541 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the nsSessionStore component.
*
* The Initial Developer of the Original Code is
* Simon Bünzli <zeniko@gmail.com>
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dietrich Ayala <autonome@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* Heavily adapted to xulrunner for the OLPC from the firefox code in
* http://lxr.mozilla.org/seamonkey/source/browser/components/sessionstore.
*
* May 2007 Tomeu Vizoso
*/
/**
* Session Storage and Restoration
*
* Overview
* This service keeps track of a user's session, storing the various bits
* required to return the browser to it's current state. The relevant data is
* stored in memory, and is periodically saved to disk in a file in the
* profile directory. The service is started at first window load, in
* delayedStartup, and will restore the session from the data received from
* the nsSessionStartup service.
*/
/* :::::::: Constants and Helpers ::::::::::::::: */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const CID = Components.ID("{5280606b-2510-4fe0-97ef-9b5a22eafe6b}");
const CONTRACT_ID = "@mozilla.org/browser/sessionstore;1";
const CLASS_NAME = "Browser Session Store Service";
// sandbox to evaluate JavaScript code from non-trustable sources
var EVAL_SANDBOX = new Components.utils.Sandbox("about:blank");
function debug(aMsg) {
aMsg = ("SessionStore: " + aMsg).replace(/\S{80}/g, "$&\n");
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
.logStringMessage(aMsg);
}
/* :::::::: The Service ::::::::::::::: */
function SessionStoreService() {
}
SessionStoreService.prototype = {
/* ........ nsISessionStore API .............. */
getBrowserState: function sss_getBrowserState(aBrowser) {
dump("nsSessionStore::getBrowserState\n")
return this._toJSONString(this._getWindowState(aBrowser));
},
setBrowserState: function sss_setBrowserState(aBrowser, aState) {
dump("nsSessionStore::setBrowserState\n")
this.restoreWindow(aBrowser, "(" + aState + ")");
},
/* ........ Saving Functionality .............. */
/**
* Store all session data for a window
* @param aSHistory
* nsISHistory reference
*/
_saveWindowHistory: function sss_saveWindowHistory(aSHistory) {
var entries = [];
dump("nsSessionStore._saveWindowHistory " + aSHistory.count);
for (var i = 0; i < aSHistory.count; i++) {
entries.push(this._serializeHistoryEntry(aSHistory.getEntryAtIndex(i, false)));
}
return entries;
},
/**
* Get an object that is a serialized representation of a History entry
* Used for data storage
* @param aEntry
* nsISHEntry instance
* @returns object
*/
_serializeHistoryEntry: function sss_serializeHistoryEntry(aEntry) {
var entry = { url: aEntry.URI.spec, children: [] };
if (aEntry.title && aEntry.title != entry.url) {
entry.title = aEntry.title;
}
if (aEntry.isSubFrame) {
entry.subframe = true;
}
if (!(aEntry instanceof Ci.nsISHEntry)) {
return entry;
}
var cacheKey = aEntry.cacheKey;
if (cacheKey && cacheKey instanceof Ci.nsISupportsPRUint32) {
entry.cacheKey = cacheKey.data;
}
entry.ID = aEntry.ID;
var x = {}, y = {};
aEntry.getScrollPosition(x, y);
entry.scroll = x.value + "," + y.value;
try {
var prefPostdata = this._prefBranch.getIntPref("sessionstore.postdata");
if (prefPostdata && aEntry.postData && this._checkPrivacyLevel(aEntry.URI.schemeIs("https"))) {
aEntry.postData.QueryInterface(Ci.nsISeekableStream).
seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
var stream = Cc["@mozilla.org/scriptableinputstream;1"].
createInstance(Ci.nsIScriptableInputStream);
stream.init(aEntry.postData);
var postdata = stream.read(stream.available());
if (prefPostdata == -1 || postdata.replace(/^(Content-.*\r\n)+(\r\n)*/, "").length <= prefPostdata) {
entry.postdata = postdata;
}
}
}
catch (ex) { debug(ex); } // POSTDATA is tricky - especially since some extensions don't get it right
if (!(aEntry instanceof Ci.nsISHContainer)) {
return entry;
}
for (var i = 0; i < aEntry.childCount; i++) {
var child = aEntry.GetChildAt(i);
if (child) {
entry.children.push(this._serializeHistoryEntry(child));
}
else { // to maintain the correct frame order, insert a dummy entry
entry.children.push({ url: "about:blank" });
}
}
return entry;
},
/**
* serialize session data for a window
* @param aBrowser
* Browser reference
* @returns string
*/
_getWindowState: function sss_getWindowState(aBrowser) {
dump("nsSessionStore::_getWindowState: " + aBrowser + "\n")
windowState = this._collectWindowData(aBrowser);
/*
this._updateCookies(windowState);
*/
return windowState;
},
_collectWindowData: function sss_collectWindowData(aBrowser) {
dump("nsSessionStore::_collectWindowData\n")
aBrowser.QueryInterface(Ci.nsIWebNavigation);
historyState = this._saveWindowHistory(aBrowser.sessionHistory);
/*
this._updateTextAndScrollData(aWindow);
this._updateCookieHosts(aWindow);
this._updateWindowFeatures(aWindow);
*/
return {history: historyState/*, textAndScroll: textAndScrollState*/};
},
/* ........ Restoring Functionality .............. */
/**
* restore features to a single window
* @param aBrowser
* Browser reference
* @param aState
* JS object or its eval'able source
*/
restoreWindow: function sss_restoreWindow(aBrowser, aState) {
try {
var winData = typeof aState == "string" ? this._safeEval(aState) : aState;
}
catch (ex) { // invalid state object - don't restore anything
debug(ex);
dump(ex);
return;
}
this.restoreHistoryPrecursor(aBrowser, winData.history);
},
/**
* Manage history restoration for a window
* @param aBrowser
* Browser reference
* @param aHistoryData
* History data to be restored
*/
restoreHistoryPrecursor: function sss_restoreHistoryPrecursor(aBrowser, aHistoryData) {
/*
// make sure that all browsers and their histories are available
// - if one's not, resume this check in 100ms (repeat at most 10 times)
for (var t = aIx; t < aTabs.length; t++) {
try {
if (!tabbrowser.getBrowserForTab(aTabs[t]._tab).webNavigation.sessionHistory) {
throw new Error();
}
}
catch (ex) { // in case browser or history aren't ready yet
if (aCount < 10) {
var restoreHistoryFunc = function(self) {
self.restoreHistoryPrecursor(aWindow, aTabs, aSelectTab, aIx, aCount + 1);
}
aWindow.setTimeout(restoreHistoryFunc, 100, this);
return;
}
}
}
*/
// helper hash for ensuring unique frame IDs
var aIdMap = { used: {} };
this.restoreHistory(aBrowser, aHistoryData, aIdMap);
},
/**
* Restory history for a window
* @param aBrowser
* Browser reference
* @param aHistoryData
* History data to be restored
* @param aIdMap
* Hash for ensuring unique frame IDs
*/
restoreHistory: function sss_restoreHistory(aBrowser, aHistoryData, aIdMap) {
dump("nsSessionStore::restoreHistory\n")
aBrowser.QueryInterface(Ci.nsIWebNavigation);
aSHistory = aBrowser.sessionHistory;
aSHistory.QueryInterface(Ci.nsISHistoryInternal);
if (aSHistory.count > 0) {
aSHistory.PurgeHistory(aSHistory.count);
}
if (!aHistoryData) {
aHistoryData = [];
}
for (var i = 0; i < aHistoryData.length; i++) {
aSHistory.addEntry(this._deserializeHistoryEntry(aHistoryData[i], aIdMap), true);
}
/*
// make sure to reset the capabilities and attributes, in case this tab gets reused
var disallow = (aHistoryData.disallow)?aHistoryData.disallow.split(","):[];
CAPABILITIES.forEach(function(aCapability) {
browser.docShell["allow" + aCapability] = disallow.indexOf(aCapability) == -1;
});
Array.filter(tab.attributes, function(aAttr) {
return (_this.xulAttributes.indexOf(aAttr.name) > -1);
}).forEach(tab.removeAttribute, tab);
if (aHistoryData.xultab) {
aHistoryData.xultab.split(" ").forEach(function(aAttr) {
if (/^([^\s=]+)=(.*)/.test(aAttr)) {
tab.setAttribute(RegExp.$1, decodeURI(RegExp.$2));
}
});
}
*/
try {
aBrowser.gotoIndex(aHistoryData.length - 1);
}
catch (ex) { dump(ex + "\n"); } // ignore an invalid aHistoryData.index
},
/**
* expands serialized history data into a session-history-entry instance
* @param aEntry
* Object containing serialized history data for a URL
* @param aIdMap
* Hash for ensuring unique frame IDs
* @returns nsISHEntry
*/
_deserializeHistoryEntry: function sss_deserializeHistoryEntry(aEntry, aIdMap) {
var shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].
createInstance(Ci.nsISHEntry);
var ioService = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
shEntry.setURI(ioService.newURI(aEntry.url, null, null));
shEntry.setTitle(aEntry.title || aEntry.url);
shEntry.setIsSubFrame(aEntry.subframe || false);
shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
if (aEntry.cacheKey) {
var cacheKey = Cc["@mozilla.org/supports-PRUint32;1"].
createInstance(Ci.nsISupportsPRUint32);
cacheKey.data = aEntry.cacheKey;
shEntry.cacheKey = cacheKey;
}
if (aEntry.ID) {
// get a new unique ID for this frame (since the one from the last
// start might already be in use)
var id = aIdMap[aEntry.ID] || 0;
if (!id) {
for (id = Date.now(); aIdMap.used[id]; id++);
aIdMap[aEntry.ID] = id;
aIdMap.used[id] = true;
}
shEntry.ID = id;
}
var scrollPos = (aEntry.scroll || "0,0").split(",");
scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
if (aEntry.postdata) {
var stream = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsIStringInputStream);
stream.setData(aEntry.postdata, -1);
shEntry.postData = stream;
}
if (aEntry.children && shEntry instanceof Ci.nsISHContainer) {
for (var i = 0; i < aEntry.children.length; i++) {
shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap), i);
}
}
return shEntry;
},
/* ........ Auxiliary Functions .............. */
/**
* don't save sensitive data if the user doesn't want to
* (distinguishes between encrypted and non-encrypted sites)
* @param aIsHTTPS
* Bool is encrypted
* @returns bool
*/
_checkPrivacyLevel: function sss_checkPrivacyLevel(aIsHTTPS) {
return this._prefBranch.getIntPref("sessionstore.privacy_level") < (aIsHTTPS ? PRIVACY_ENCRYPTED : PRIVACY_FULL);
},
/**
* safe eval'ing
*/
_safeEval: function sss_safeEval(aStr) {
return Components.utils.evalInSandbox(aStr, EVAL_SANDBOX);
},
/**
* Converts a JavaScript object into a JSON string
* (see http://www.json.org/ for the full grammar).
*
* The inverse operation consists of eval("(" + JSON_string + ")");
* and should be provably safe.
*
* @param aJSObject is the object to be converted
* @return the object's JSON representation
*/
_toJSONString: function sss_toJSONString(aJSObject) {
// these characters have a special escape notation
const charMap = { "\b": "\\b", "\t": "\\t", "\n": "\\n", "\f": "\\f",
"\r": "\\r", '"': '\\"', "\\": "\\\\" };
// we use a single string builder for efficiency reasons
var parts = [];
// this recursive function walks through all objects and appends their
// JSON representation to the string builder
function jsonIfy(aObj) {
if (typeof aObj == "boolean") {
parts.push(aObj ? "true" : "false");
}
else if (typeof aObj == "number" && isFinite(aObj)) {
// there is no representation for infinite numbers or for NaN!
parts.push(aObj.toString());
}
else if (typeof aObj == "string") {
aObj = aObj.replace(/[\\"\x00-\x1F\u0080-\uFFFF]/g, function($0) {
// use the special escape notation if one exists, otherwise
// produce a general unicode escape sequence
return charMap[$0] ||
"\\u" + ("0000" + $0.charCodeAt(0).toString(16)).slice(-4);
});
parts.push('"' + aObj + '"')
}
else if (aObj == null) {
parts.push("null");
}
else if (aObj instanceof Array || aObj instanceof EVAL_SANDBOX.Array) {
parts.push("[");
for (var i = 0; i < aObj.length; i++) {
jsonIfy(aObj[i]);
parts.push(",");
}
if (parts[parts.length - 1] == ",")
parts.pop(); // drop the trailing colon
parts.push("]");
}
else if (typeof aObj == "object") {
parts.push("{");
for (var key in aObj) {
jsonIfy(key.toString());
parts.push(":");
jsonIfy(aObj[key]);
parts.push(",");
}
if (parts[parts.length - 1] == ",")
parts.pop(); // drop the trailing colon
parts.push("}");
}
else {
throw new Error("No JSON representation for this object!");
}
}
jsonIfy(aJSObject);
var newJSONString = parts.join(" ");
// sanity check - so that API consumers can just eval this string
if (/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
newJSONString.replace(/"(\\.|[^"\\])*"/g, "")
))
throw new Error("JSON conversion failed unexpectedly!");
return newJSONString;
},
/* ........ QueryInterface .............. */
QueryInterface: function(aIID) {
if (!aIID.equals(Ci.nsISupports) &&
!aIID.equals(Ci.nsIObserver) &&
!aIID.equals(Ci.nsISupportsWeakReference) &&
!aIID.equals(Ci.nsIDOMEventListener) &&
!aIID.equals(Ci.nsISessionStore)) {
Components.returnCode = Cr.NS_ERROR_NO_INTERFACE;
return null;
}
return this;
}
};
/* :::::::: Service Registration & Initialization ::::::::::::::: */
/* ........ nsIModule .............. */
const SessionStoreModule = {
getClassObject: function(aCompMgr, aCID, aIID) {
if (aCID.equals(CID)) {
return SessionStoreFactory;
}
Components.returnCode = Cr.NS_ERROR_NOT_REGISTERED;
return null;
},
registerSelf: function(aCompMgr, aFileSpec, aLocation, aType) {
aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
aCompMgr.registerFactoryLocation(CID, CLASS_NAME, CONTRACT_ID, aFileSpec, aLocation, aType);
},
unregisterSelf: function(aCompMgr, aLocation, aType) {
aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
aCompMgr.unregisterFactoryLocation(CID, aLocation);
},
canUnload: function(aCompMgr) {
return true;
}
}
/* ........ nsIFactory .............. */
const SessionStoreFactory = {
createInstance: function(aOuter, aIID) {
if (aOuter != null) {
Components.returnCode = Cr.NS_ERROR_NO_AGGREGATION;
return null;
}
return (new SessionStoreService()).QueryInterface(aIID);
},
lockFactory: function(aLock) { },
QueryInterface: function(aIID) {
if (!aIID.equals(Ci.nsISupports) && !aIID.equals(Ci.nsIModule) &&
!aIID.equals(Ci.nsIFactory) && !aIID.equals(Ci.nsISessionStore)) {
Components.returnCode = Cr.NS_ERROR_NO_INTERFACE;
return null;
}
return this;
}
};
function NSGetModule(aComMgr, aFileSpec) {
dump("nsSessionStore: NSGetModule\n")
return SessionStoreModule;
}

View File

@ -1,962 +0,0 @@
/*
* Copyright (C) 2006, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <config.h>
#include "sugar-browser.h"
#include "sugar-marshal.h"
#include "GeckoContentHandler.h"
#include "GeckoDownload.h"
#include "GeckoDragDropHooks.h"
#include "GeckoDocumentObject.h"
#include "GeckoBrowserPersist.h"
#include "GeckoDirectoryProvider.h"
#include <gdk/gdkx.h>
#include <gtkmozembed_internal.h>
#include <nsCOMPtr.h>
#include <nsIPrefService.h>
#include <nsServiceManagerUtils.h>
#include <nsStringAPI.h>
#include <nsILocalFile.h>
#include <nsIWebBrowser.h>
#include <nsIWebBrowserFocus.h>
#include <nsIWebBrowserPersist.h>
#include <nsIDOMWindow.h>
#include <nsIDOMWindowUtils.h>
#include <nsIDOMDocument.h>
#include <nsIDOMMouseEvent.h>
#include <nsIGenericFactory.h>
#include <nsIHelperAppLauncherDialog.h>
#include <nsIComponentRegistrar.h>
#include <nsIDOMNode.h>
#include <nsIDOMEventTarget.h>
#include <nsIDOMHTMLImageElement.h>
#include <nsIIOService.h>
#include <nsComponentManagerUtils.h>
#include <imgICache.h>
#include <nsIProperties.h>
#include <nsIWebNavigation.h>
#include <nsISupportsPrimitives.h>
#include <nsIInterfaceRequestorUtils.h>
#include <nsIMIMEHeaderParam.h>
#include <nsISHistory.h>
#include <nsIHistoryEntry.h>
#include <nsISHEntry.h>
#include <nsIInputStream.h>
#include <nsICommandManager.h>
#include <nsIClipboardDragDropHooks.h>
#include "nsISessionStore.h"
#include "nsIBrowserHelper.h"
#define SUGAR_PATH "SUGAR_PATH"
enum {
PROP_0,
PROP_PROGRESS,
PROP_TITLE,
PROP_ADDRESS,
PROP_CAN_GO_BACK,
PROP_CAN_GO_FORWARD,
PROP_LOADING,
PROP_DOCUMENT_METADATA
};
enum {
MOUSE_CLICK,
N_SIGNALS
};
static int last_instance_id = 0;
static guint signals[N_SIGNALS];
static GObjectClass *parent_class = NULL;
static const nsModuleComponentInfo sSugarComponents[] = {
{
"Gecko Content Handler",
GECKOCONTENTHANDLER_CID,
NS_IHELPERAPPLAUNCHERDLG_CONTRACTID,
NULL
},
{
"Gecko Download",
GECKODOWNLOAD_CID,
NS_TRANSFER_CONTRACTID,
NULL
}
};
int (*old_handler) (Display *, XErrorEvent *);
static int
error_handler (Display *d, XErrorEvent *e)
{
gchar buf[64];
gchar *msg;
XGetErrorText(d, e->error_code, buf, 63);
msg =
g_strdup_printf("The program '%s' received an X Window System error.\n"
"This probably reflects a bug in the program.\n"
"The error was '%s'.\n"
" (Details: serial %ld error_code %d request_code %d minor_code %d)\n",
g_get_prgname (),
buf,
e->serial,
e->error_code,
e->request_code,
e->minor_code);
g_warning ("%s", msg);
return 0;
/*return (*old_handler)(d, e);*/
}
static void
setup_plugin_path ()
{
const char *user_path;
char *new_path;
user_path = g_getenv ("MOZ_PLUGIN_PATH");
new_path = g_strconcat (user_path ? user_path : "",
user_path ? ":" : "",
PLUGIN_DIR,
(char *) NULL);
g_setenv ("MOZ_PLUGIN_PATH", new_path, TRUE);
g_free (new_path);
}
static gboolean
setup_directory_provider(const char *full_prof_path)
{
const char *prefix = g_getenv("SUGAR_PREFIX");
if (prefix == NULL) {
g_print("The SUGAR_PREFIX environment variable is not set.");
exit(1);
}
char *components_path = g_build_filename(prefix, "share/sugar", NULL);
GeckoDirectoryProvider *dirProvider =
new GeckoDirectoryProvider(components_path, full_prof_path);
if (!dirProvider) {
g_warning ("failed to create GeckoDirectoryProvider");
return FALSE;
}
g_free(components_path);
NS_ADDREF (dirProvider);
nsCOMPtr<nsIDirectoryServiceProvider> dp (do_QueryInterface (dirProvider));
NS_RELEASE (dirProvider);
dirProvider = nsnull;
if (!dp) return FALSE;
gtk_moz_embed_set_directory_service_provider(dp);
return TRUE;
}
gboolean
sugar_browser_startup(const char *profile_path, const char *profile_name)
{
nsresult rv;
setup_plugin_path();
gtk_moz_embed_set_profile_path(profile_path, profile_name);
old_handler = XSetErrorHandler(error_handler);
char *full_prof_path = g_build_filename(profile_path, profile_name, NULL);
if (!setup_directory_provider(full_prof_path)) {
return FALSE;
}
g_free(full_prof_path);
gtk_moz_embed_push_startup();
nsCOMPtr<nsIPrefService> prefService;
prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
NS_ENSURE_TRUE(prefService, FALSE);
/* Read our predefined default prefs */
nsCString pathToPrefs(g_getenv(SUGAR_PATH));
pathToPrefs.Append("/data/gecko-prefs.js");
nsCOMPtr<nsILocalFile> file;
NS_NewNativeLocalFile(pathToPrefs, PR_TRUE, getter_AddRefs(file));
NS_ENSURE_TRUE(file, FALSE);
rv = prefService->ReadUserPrefs (file);
if (NS_FAILED(rv)) {
g_warning ("failed to read default preferences, error: %x", rv);
return FALSE;
}
nsCOMPtr<nsIPrefBranch> pref;
prefService->GetBranch ("", getter_AddRefs(pref));
NS_ENSURE_TRUE(pref, FALSE);
nsCString pathToMimeTypes(g_getenv(SUGAR_PATH));
pathToMimeTypes.Append("/data/mime.types");
pref->SetCharPref ("helpers.private_mime_types_file", pathToMimeTypes.get());
rv = prefService->ReadUserPrefs (nsnull);
if (NS_FAILED(rv)) {
g_warning ("failed to read user preferences, error: %x", rv);
}
nsCOMPtr<nsIComponentRegistrar> componentRegistrar;
NS_GetComponentRegistrar(getter_AddRefs(componentRegistrar));
NS_ENSURE_TRUE (componentRegistrar, FALSE);
nsCOMPtr<nsIFactory> contentHandlerFactory;
rv = NS_NewGeckoContentHandlerFactory(getter_AddRefs(contentHandlerFactory));
rv = componentRegistrar->RegisterFactory(sSugarComponents[0].mCID,
sSugarComponents[0].mDescription,
sSugarComponents[0].mContractID,
contentHandlerFactory);
if (NS_FAILED(rv)) {
g_warning ("Failed to register factory for %s\n", sSugarComponents[0].mDescription);
return FALSE;
}
nsCOMPtr<nsIFactory> downloadFactory;
rv = NS_NewGeckoDownloadFactory(getter_AddRefs(downloadFactory));
rv = componentRegistrar->RegisterFactory(sSugarComponents[1].mCID,
sSugarComponents[1].mDescription,
sSugarComponents[1].mContractID,
downloadFactory);
if (NS_FAILED(rv)) {
g_warning ("Failed to register factory for %s\n", sSugarComponents[1].mDescription);
return FALSE;
}
return TRUE;
}
void
sugar_browser_shutdown(void)
{
gtk_moz_embed_pop_startup();
}
G_DEFINE_TYPE(SugarBrowser, sugar_browser, GTK_TYPE_MOZ_EMBED)
static nsresult
FilenameFromContentDisposition(nsCString contentDisposition, nsCString &fileName)
{
nsresult rv;
nsCString fallbackCharset;
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
do_GetService("@mozilla.org/network/mime-hdrparam;1");
NS_ENSURE_TRUE(mimehdrpar, NS_ERROR_FAILURE);
nsString aFileName;
rv = mimehdrpar->GetParameter (contentDisposition, "filename",
fallbackCharset, PR_TRUE, nsnull,
aFileName);
if (NS_FAILED(rv) || !fileName.Length()) {
rv = mimehdrpar->GetParameter (contentDisposition, "name",
fallbackCharset, PR_TRUE, nsnull,
aFileName);
}
if (NS_SUCCEEDED(rv) && fileName.Length()) {
NS_UTF16ToCString (aFileName, NS_CSTRING_ENCODING_UTF8, fileName);
}
return NS_OK;
}
static SugarBrowserMetadata *
sugar_browser_get_document_metadata(SugarBrowser *browser)
{
SugarBrowserMetadata *metadata = sugar_browser_metadata_new();
nsCOMPtr<nsIWebBrowser> webBrowser;
gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser),
getter_AddRefs(webBrowser));
NS_ENSURE_TRUE(webBrowser, metadata);
nsCOMPtr<nsIDOMWindow> DOMWindow;
webBrowser->GetContentDOMWindow(getter_AddRefs(DOMWindow));
NS_ENSURE_TRUE(DOMWindow, metadata);
nsCOMPtr<nsIDOMWindowUtils> DOMWindowUtils(do_GetInterface(DOMWindow));
NS_ENSURE_TRUE(DOMWindowUtils, metadata);
const PRUnichar contentDispositionLiteral[] =
{'c', 'o', 'n', 't', 'e', 'n', 't', '-', 'd', 'i', 's', 'p',
'o', 's', 'i', 't', 'i', 'o', 'n', '\0'};
nsString contentDisposition;
DOMWindowUtils->GetDocumentMetadata(nsString(contentDispositionLiteral),
contentDisposition);
nsCString cContentDisposition;
NS_UTF16ToCString (contentDisposition, NS_CSTRING_ENCODING_UTF8,
cContentDisposition);
nsCString fileName;
FilenameFromContentDisposition(cContentDisposition, fileName);
if (!fileName.Length()) {
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(webBrowser));
if (webNav) {
nsCOMPtr<nsIURI> docURI;
webNav->GetCurrentURI (getter_AddRefs(docURI));
nsCOMPtr<nsIURL> url(do_QueryInterface(docURI));
if (url) {
url->GetFileName(fileName);
}
}
}
if (fileName.Length()) {
metadata->filename = g_strdup(fileName.get());
}
return metadata;
}
static void
sugar_browser_get_property(GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SugarBrowser *browser = SUGAR_BROWSER(object);
switch (prop_id) {
case PROP_PROGRESS:
g_value_set_double(value, browser->progress);
break;
case PROP_ADDRESS:
g_value_set_string(value, browser->address);
break;
case PROP_TITLE:
g_value_set_string(value, browser->title);
break;
case PROP_CAN_GO_BACK:
g_value_set_boolean(value, browser->can_go_back);
break;
case PROP_CAN_GO_FORWARD:
g_value_set_boolean(value, browser->can_go_forward);
break;
case PROP_LOADING:
g_value_set_boolean(value, browser->loading);
break;
case PROP_DOCUMENT_METADATA:
SugarBrowserMetadata *metadata;
metadata = sugar_browser_get_document_metadata(browser);
g_value_set_boxed(value, metadata);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
sugar_browser_realize(GtkWidget *widget)
{
SugarBrowser *browser = SUGAR_BROWSER(widget);
GTK_WIDGET_CLASS(parent_class)->realize(widget);
GtkMozEmbed *embed = GTK_MOZ_EMBED(widget);
nsCOMPtr<nsIWebBrowser> webBrowser;
gtk_moz_embed_get_nsIWebBrowser(embed, getter_AddRefs(webBrowser));
NS_ENSURE_TRUE(webBrowser, );
nsCOMPtr<nsIBrowserHelper> browserHelper;
browserHelper = do_GetService("@laptop.org/browser/browserhelper;1");
if (browserHelper) {
browserHelper->RegisterBrowser(browser->instance_id, webBrowser);
} else {
g_warning ("Failed to get nsIBrowserHelper");
}
nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(webBrowser);
if (commandManager) {
nsresult rv;
nsIClipboardDragDropHooks *rawPtr = new GeckoDragDropHooks(
SUGAR_BROWSER(widget));
nsCOMPtr<nsIClipboardDragDropHooks> geckoDragDropHooks(
do_QueryInterface(rawPtr, &rv));
NS_ENSURE_SUCCESS(rv, );
nsCOMPtr<nsIDOMWindow> DOMWindow = do_GetInterface(webBrowser);
nsCOMPtr<nsICommandParams> cmdParamsObj = do_CreateInstance(
NS_COMMAND_PARAMS_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, );
cmdParamsObj->SetISupportsValue("addhook", geckoDragDropHooks);
commandManager->DoCommand("cmd_clipboardDragDropHook", cmdParamsObj,
DOMWindow);
}
}
static void
sugar_browser_dispose(GObject *object)
{
SugarBrowser *browser = SUGAR_BROWSER(object);
GtkMozEmbed *embed = GTK_MOZ_EMBED(object);
nsCOMPtr<nsIWebBrowser> webBrowser;
gtk_moz_embed_get_nsIWebBrowser(embed, getter_AddRefs(webBrowser));
NS_ENSURE_TRUE(webBrowser, );
nsCOMPtr<nsIBrowserHelper> browserHelper;
browserHelper = do_GetService("@laptop.org/browser/browserhelper;1");
if (browserHelper) {
browserHelper->UnregisterBrowser(browser->instance_id);
} else {
g_warning ("Failed to get nsIBrowserHelper");
}
}
static void
sugar_browser_class_init(SugarBrowserClass *browser_class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(browser_class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(browser_class);
parent_class = (GObjectClass *) g_type_class_peek_parent(browser_class);
gobject_class->get_property = sugar_browser_get_property;
gobject_class->dispose = sugar_browser_dispose;
widget_class->realize = sugar_browser_realize;
signals[MOUSE_CLICK] = g_signal_new ("mouse_click",
SUGAR_TYPE_BROWSER,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(SugarBrowser, mouse_click),
g_signal_accumulator_true_handled, NULL,
sugar_marshal_BOOLEAN__BOXED,
G_TYPE_BOOLEAN,
1,
SUGAR_TYPE_BROWSER_EVENT);
g_object_class_install_property(gobject_class, PROP_PROGRESS,
g_param_spec_double ("progress",
"Progress",
"Progress",
0.0, 1.0, 0.0,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class, PROP_ADDRESS,
g_param_spec_string ("address",
"Address",
"Address",
"",
G_PARAM_READABLE));
g_object_class_install_property (gobject_class, PROP_TITLE,
g_param_spec_string ("title",
"Title",
"Title",
"",
G_PARAM_READABLE));
g_object_class_install_property (gobject_class, PROP_CAN_GO_BACK,
g_param_spec_boolean ("can-go-back",
"Can go back",
"Can go back",
FALSE,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class, PROP_CAN_GO_FORWARD,
g_param_spec_boolean ("can-go-forward",
"Can go forward",
"Can go forward",
FALSE,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class, PROP_LOADING,
g_param_spec_boolean ("loading",
"Loading",
"Loading",
FALSE,
G_PARAM_READABLE));
g_object_class_install_property(gobject_class, PROP_DOCUMENT_METADATA,
g_param_spec_boxed("document-metadata",
"Document Metadata",
"Document metadata",
SUGAR_TYPE_BROWSER_METADATA,
G_PARAM_READABLE));
}
SugarBrowser *
sugar_browser_create_window(SugarBrowser *browser)
{
return SUGAR_BROWSER_GET_CLASS(browser)->create_window(browser);
}
static void
update_navigation_properties(SugarBrowser *browser)
{
GtkMozEmbed *embed = GTK_MOZ_EMBED(browser);
gboolean can_go_back;
gboolean can_go_forward;
can_go_back = gtk_moz_embed_can_go_back(embed);
if (can_go_back != browser->can_go_back) {
browser->can_go_back = can_go_back;
g_object_notify (G_OBJECT(browser), "can-go-back");
}
can_go_forward = gtk_moz_embed_can_go_forward(embed);
if (can_go_forward != browser->can_go_forward) {
browser->can_go_forward = can_go_forward;
g_object_notify (G_OBJECT(browser), "can-go-forward");
}
}
static void
new_window_cb(GtkMozEmbed *embed,
GtkMozEmbed **newEmbed,
guint chromemask)
{
SugarBrowser *browser;
browser = sugar_browser_create_window(SUGAR_BROWSER(embed));
*newEmbed = GTK_MOZ_EMBED(browser);
}
static void
sugar_browser_set_progress(SugarBrowser *browser, float progress)
{
g_return_if_fail(SUGAR_IS_BROWSER(browser));
browser->progress = progress;
g_object_notify (G_OBJECT(browser), "progress");
}
static void
sugar_browser_set_loading(SugarBrowser *browser, gboolean loading)
{
g_return_if_fail(SUGAR_IS_BROWSER(browser));
browser->loading = loading;
g_object_notify (G_OBJECT(browser), "loading");
}
static void
net_state_cb(GtkMozEmbed *embed, const char *aURI, gint state, guint status)
{
SugarBrowser *browser = SUGAR_BROWSER(embed);
if (state & GTK_MOZ_EMBED_FLAG_IS_NETWORK) {
if (state & GTK_MOZ_EMBED_FLAG_START) {
browser->total_requests = 0;
browser->current_requests = 0;
sugar_browser_set_progress(browser, 0.03);
sugar_browser_set_loading(browser, TRUE);
update_navigation_properties(browser);
} else if (state & GTK_MOZ_EMBED_FLAG_STOP) {
sugar_browser_set_progress(browser, 1.0);
sugar_browser_set_loading(browser, FALSE);
update_navigation_properties(browser);
}
}
if (state & GTK_MOZ_EMBED_FLAG_IS_REQUEST) {
float progress;
if (state & GTK_MOZ_EMBED_FLAG_START) {
browser->total_requests++;
}
else if (state & GTK_MOZ_EMBED_FLAG_STOP)
{
browser->current_requests++;
}
progress = float(browser->current_requests) /
float(browser->total_requests);
if (progress > browser->progress) {
sugar_browser_set_progress(browser, progress);
}
}
}
static void
title_cb(GtkMozEmbed *embed)
{
SugarBrowser *browser = SUGAR_BROWSER(embed);
g_free(browser->title);
browser->title = gtk_moz_embed_get_title(embed);
g_object_notify (G_OBJECT(browser), "title");
}
static void
location_cb(GtkMozEmbed *embed)
{
SugarBrowser *browser = SUGAR_BROWSER(embed);
g_free(browser->address);
browser->address = gtk_moz_embed_get_location(embed);
g_object_notify (G_OBJECT(browser), "address");
update_navigation_properties(browser);
}
static gboolean
dom_mouse_click_cb(GtkMozEmbed *embed, nsIDOMMouseEvent *mouseEvent)
{
SugarBrowser *browser = SUGAR_BROWSER(embed);
SugarBrowserEvent *event;
gint return_value = FALSE;
nsCOMPtr<nsIDOMEventTarget> eventTarget;
mouseEvent->GetTarget(getter_AddRefs(eventTarget));
NS_ENSURE_TRUE(mouseEvent, FALSE);
nsCOMPtr<nsIDOMNode> targetNode;
targetNode = do_QueryInterface(eventTarget);
NS_ENSURE_TRUE(targetNode, FALSE);
event = sugar_browser_event_new();
GeckoDocumentObject documentObject(browser, targetNode);
if(documentObject.IsImage()) {
event->image_uri = documentObject.GetImageURI();
event->image_name = documentObject.GetImageName();
}
PRUint16 btn = 0;
mouseEvent->GetButton (&btn);
event->button = btn + 1;
g_signal_emit(browser, signals[MOUSE_CLICK], 0, event, &return_value);
sugar_browser_event_free(event);
return return_value;
}
static void
sugar_browser_init(SugarBrowser *browser)
{
browser->instance_id = last_instance_id;
last_instance_id++;
browser->title = NULL;
browser->address = NULL;
browser->progress = 0.0;
g_signal_connect(G_OBJECT(browser), "new-window",
G_CALLBACK(new_window_cb), NULL);
g_signal_connect(G_OBJECT(browser), "net-state-all",
G_CALLBACK(net_state_cb), NULL);
g_signal_connect(G_OBJECT(browser), "title",
G_CALLBACK(title_cb), NULL);
g_signal_connect(G_OBJECT(browser), "location",
G_CALLBACK(location_cb), NULL);
/* g_signal_connect(G_OBJECT(browser), "dom-mouse-click",
G_CALLBACK(dom_mouse_click_cb), NULL);
*/
}
int
sugar_browser_get_instance_id(SugarBrowser *browser)
{
return browser->instance_id;
}
void
sugar_browser_scroll_pixels(SugarBrowser *browser,
int dx,
int dy)
{
nsCOMPtr<nsIWebBrowser> webBrowser;
gtk_moz_embed_get_nsIWebBrowser (GTK_MOZ_EMBED(browser),
getter_AddRefs(webBrowser));
NS_ENSURE_TRUE (webBrowser, );
nsCOMPtr<nsIWebBrowserFocus> webBrowserFocus;
webBrowserFocus = do_QueryInterface (webBrowser);
NS_ENSURE_TRUE (webBrowserFocus, );
nsCOMPtr<nsIDOMWindow> DOMWindow;
webBrowserFocus->GetFocusedWindow (getter_AddRefs(DOMWindow));
if (!DOMWindow) {
webBrowser->GetContentDOMWindow (getter_AddRefs(DOMWindow));
}
NS_ENSURE_TRUE (DOMWindow, );
DOMWindow->ScrollBy (dx, dy);
}
void
sugar_browser_grab_focus(SugarBrowser *browser)
{
GtkWidget *child;
child = gtk_bin_get_child(GTK_BIN(browser));
if (child != NULL) {
gtk_widget_grab_focus (child);
} else {
g_warning ("Need to realize the embed before grabbing focus!\n");
}
}
gboolean
sugar_browser_save_uri(SugarBrowser *browser,
const char *uri,
const char *filename)
{
GeckoBrowserPersist browserPersist(browser);
return browserPersist.SaveURI(uri, filename);
}
gboolean
sugar_browser_save_document(SugarBrowser *browser,
const char *filename)
{
nsresult rv;
nsCString cFile(filename);
nsCOMPtr<nsILocalFile> destFile = do_CreateInstance("@mozilla.org/file/local;1");
NS_ENSURE_TRUE(destFile, FALSE);
destFile->InitWithNativePath(cFile);
GString *path = g_string_new (filename);
char *dot_pos = strchr (path->str, '.');
if (dot_pos) {
g_string_truncate (path, dot_pos - path->str);
}
g_string_append (path, " Files");
nsCOMPtr<nsILocalFile> filesFolder;
filesFolder = do_CreateInstance ("@mozilla.org/file/local;1");
filesFolder->InitWithNativePath (nsCString(path->str));
g_string_free (path, TRUE);
nsCOMPtr<nsIWebBrowser> webBrowser;
gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser),
getter_AddRefs(webBrowser));
NS_ENSURE_TRUE(webBrowser, FALSE);
nsCOMPtr<nsIDOMWindow> DOMWindow;
webBrowser->GetContentDOMWindow(getter_AddRefs(DOMWindow));
NS_ENSURE_TRUE(DOMWindow, FALSE);
nsCOMPtr<nsIDOMDocument> DOMDocument;
DOMWindow->GetDocument (getter_AddRefs(DOMDocument));
NS_ENSURE_TRUE(DOMDocument, FALSE);
nsCOMPtr<nsIWebBrowserPersist> webPersist = do_QueryInterface (webBrowser);
NS_ENSURE_TRUE(webPersist, FALSE);
rv = webPersist->SaveDocument(DOMDocument, destFile, filesFolder, nsnull, 0, 0);
NS_ENSURE_SUCCESS(rv, FALSE);
return TRUE;
}
char *
sugar_browser_get_session(SugarBrowser *browser)
{
nsCOMPtr<nsIWebBrowser> webBrowser;
gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser),
getter_AddRefs(webBrowser));
if (!webBrowser) {
g_warning ("failed to get nsIWebBrowser");
return NULL;
}
nsCOMPtr<nsISessionStore> sessionStore;
sessionStore = do_GetService("@mozilla.org/browser/sessionstore;1");
if (!sessionStore) {
g_warning ("failed to get nsISessionStore");
return NULL;
}
nsString session;
nsresult rv = sessionStore->GetBrowserState(webBrowser, session);
if (NS_FAILED(rv)) {
g_warning ("failed to get browser state");
return NULL;
}
nsCString sessionUTF8;
NS_UTF16ToCString (session, NS_CSTRING_ENCODING_UTF8, sessionUTF8);
return g_strdup(sessionUTF8.get());
}
gboolean
sugar_browser_set_session(SugarBrowser *browser,
const char *session)
{
nsCOMPtr<nsIWebBrowser> webBrowser;
gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser),
getter_AddRefs(webBrowser));
if (!webBrowser) {
g_warning ("failed to get nsIWebBrowser");
return FALSE;
}
nsCOMPtr<nsISessionStore> sessionStore;
sessionStore = do_GetService("@mozilla.org/browser/sessionstore;1");
if (!sessionStore) {
g_warning ("failed to get nsISessionStore");
return FALSE;
}
nsCString sessionUTF8(session);
nsString sessionUTF16;
NS_CStringToUTF16(sessionUTF8, NS_CSTRING_ENCODING_UTF8, sessionUTF16);
nsresult rv = sessionStore->SetBrowserState(webBrowser, sessionUTF16);
if (NS_FAILED(rv)) {
g_warning ("failed to set browser state");
return FALSE;
}
return TRUE;
}
GType
sugar_browser_event_get_type(void)
{
static GType type = 0;
if (G_UNLIKELY(type == 0)) {
type = g_boxed_type_register_static("SugarBrowserEvent",
(GBoxedCopyFunc)sugar_browser_event_copy,
(GBoxedFreeFunc)sugar_browser_event_free);
}
return type;
}
SugarBrowserEvent *
sugar_browser_event_new(void)
{
SugarBrowserEvent *event;
event = g_new0(SugarBrowserEvent, 1);
return event;
}
SugarBrowserEvent *
sugar_browser_event_copy(SugarBrowserEvent *event)
{
SugarBrowserEvent *copy;
g_return_val_if_fail(event != NULL, NULL);
copy = g_new0(SugarBrowserEvent, 1);
copy->button = event->button;
copy->image_uri = g_strdup(event->image_uri);
copy->image_name = g_strdup(event->image_name);
return copy;
}
void
sugar_browser_event_free(SugarBrowserEvent *event)
{
g_return_if_fail(event != NULL);
if (event->image_uri) {
g_free(event->image_uri);
}
if (event->image_name) {
g_free(event->image_name);
}
g_free(event);
}
GType
sugar_browser_metadata_get_type(void)
{
static GType type = 0;
if (G_UNLIKELY(type == 0)) {
type = g_boxed_type_register_static("SugarBrowserMetadata",
(GBoxedCopyFunc)sugar_browser_metadata_copy,
(GBoxedFreeFunc)sugar_browser_metadata_free);
}
return type;
}
SugarBrowserMetadata *
sugar_browser_metadata_new(void)
{
SugarBrowserMetadata *metadata;
metadata = g_new0(SugarBrowserMetadata, 1);
return metadata;
}
SugarBrowserMetadata *
sugar_browser_metadata_copy(SugarBrowserMetadata *metadata)
{
SugarBrowserMetadata *copy;
g_return_val_if_fail(metadata != NULL, NULL);
copy = g_new0(SugarBrowserMetadata, 1);
copy->filename = g_strdup(metadata->filename);
return copy;
}
void
sugar_browser_metadata_free(SugarBrowserMetadata *metadata)
{
g_return_if_fail(metadata != NULL);
if (metadata->filename) {
g_free(metadata->filename);
}
g_free(metadata);
}

View File

@ -1,108 +0,0 @@
/*
* Copyright (C) 2006, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __SUGAR_BROWSER_H__
#define __SUGAR_BROWSER_H__
#include <gtkmozembed.h>
G_BEGIN_DECLS
typedef struct _SugarBrowser SugarBrowser;
typedef struct _SugarBrowserClass SugarBrowserClass;
typedef struct _SugarBrowserEvent SugarBrowserEvent;
typedef struct _SugarBrowserMetadata SugarBrowserMetadata;
#define SUGAR_TYPE_BROWSER (sugar_browser_get_type())
#define SUGAR_BROWSER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), SUGAR_TYPE_BROWSER, SugarBrowser))
#define SUGAR_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SUGAR_TYPE_BROWSER, SugarBrowserClass))
#define SUGAR_IS_BROWSER(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), SUGAR_TYPE_BROWSER))
#define SUGAR_IS_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SUGAR_TYPE_BROWSER))
#define SUGAR_BROWSER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), SUGAR_TYPE_BROWSER, SugarBrowserClass))
struct _SugarBrowser {
GtkMozEmbed base_instance;
int instance_id;
int total_requests;
int current_requests;
float progress;
char *address;
char *title;
gboolean can_go_back;
gboolean can_go_forward;
gboolean loading;
gboolean (* mouse_click) (SugarBrowser *browser,
SugarBrowserEvent *event);
};
struct _SugarBrowserClass {
GtkMozEmbedClass base_class;
SugarBrowser * (* create_window) (SugarBrowser *browser);
};
GType sugar_browser_get_type (void);
int sugar_browser_get_instance_id (SugarBrowser *browser);
SugarBrowser *sugar_browser_create_window (SugarBrowser *browser);
void sugar_browser_scroll_pixels (SugarBrowser *browser,
int dx,
int dy);
void sugar_browser_grab_focus (SugarBrowser *browser);
gboolean sugar_browser_save_uri (SugarBrowser *browser,
const char *uri,
const char *filename);
gboolean sugar_browser_save_document (SugarBrowser *browser,
const char *filename);
char *sugar_browser_get_session (SugarBrowser *browser);
gboolean sugar_browser_set_session (SugarBrowser *browser,
const char *session);
gboolean sugar_browser_startup (const char *profile_path,
const char *profile_name);
void sugar_browser_shutdown (void);
#define SUGAR_TYPE_BROWSER_EVENT (sugar_browser_event_get_type())
struct _SugarBrowserEvent {
int button;
char *image_uri;
char *image_name;
};
GType sugar_browser_event_get_type (void);
SugarBrowserEvent *sugar_browser_event_new (void);
SugarBrowserEvent *sugar_browser_event_copy (SugarBrowserEvent *event);
void sugar_browser_event_free (SugarBrowserEvent *event);
#define SUGAR_TYPE_BROWSER_METADATA (sugar_browser_metadata_get_type())
struct _SugarBrowserMetadata {
char *filename;
};
GType sugar_browser_metadata_get_type (void);
SugarBrowserMetadata *sugar_browser_metadata_new (void);
SugarBrowserMetadata *sugar_browser_metadata_copy (SugarBrowserMetadata *event);
void sugar_browser_metadata_free (SugarBrowserMetadata *event);
G_END_DECLS
#endif

View File

@ -1,165 +0,0 @@
#include "sugar-marshal.h"
#include "sugar-download.h"
#include "sugar-download-manager.h"
enum {
DOWNLOAD_STARTED,
DOWNLOAD_COMPLETED,
DOWNLOAD_CANCELLED,
DOWNLOAD_PROGRESS,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
static void sugar_download_manager_finalize (GObject *object);
static void sugar_download_remove_download (gpointer key, gpointer value, gpointer user_data);
G_DEFINE_TYPE (SugarDownloadManager, sugar_download_manager, G_TYPE_OBJECT)
SugarDownloadManager *DownloadManager = NULL;
static void
sugar_download_manager_init (SugarDownloadManager *download_manager)
{
download_manager->downloads = g_hash_table_new (g_str_hash, g_str_equal);
}
static void
sugar_download_manager_class_init (SugarDownloadManagerClass *download_manager_class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (download_manager_class);
gobject_class->finalize = sugar_download_manager_finalize;
signals[DOWNLOAD_STARTED] =
g_signal_new ("download-started",
G_OBJECT_CLASS_TYPE (download_manager_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (SugarDownloadManagerClass, handle_content),
NULL, NULL,
sugar_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
G_TYPE_OBJECT);
signals[DOWNLOAD_COMPLETED] =
g_signal_new ("download-completed",
G_OBJECT_CLASS_TYPE (download_manager_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (SugarDownloadManagerClass, handle_content),
NULL, NULL,
sugar_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
G_TYPE_OBJECT);
signals[DOWNLOAD_CANCELLED] =
g_signal_new ("download-cancelled",
G_OBJECT_CLASS_TYPE (download_manager_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (SugarDownloadManagerClass, handle_content),
NULL, NULL,
sugar_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
G_TYPE_OBJECT);
signals[DOWNLOAD_PROGRESS] =
g_signal_new ("download-progress",
G_OBJECT_CLASS_TYPE (download_manager_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (SugarDownloadManagerClass, handle_content),
NULL, NULL,
sugar_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
G_TYPE_OBJECT);
}
static void
sugar_download_manager_finalize (GObject *object)
{
SugarDownloadManager *download_manager = SUGAR_DOWNLOAD_MANAGER (object);
g_hash_table_foreach (download_manager->downloads, sugar_download_remove_download, NULL);
g_hash_table_destroy (download_manager->downloads);
}
static void
sugar_download_remove_download (gpointer key, gpointer value, gpointer user_data)
{
g_free (value);
}
SugarDownloadManager *
sugar_get_download_manager ()
{
if (DownloadManager == NULL)
DownloadManager = g_object_new (SUGAR_TYPE_DOWNLOAD_MANAGER, NULL);
return DownloadManager;
}
void
sugar_download_manager_download_started (SugarDownloadManager *download_manager,
const char *url,
const char *mime_type,
const char *file_name)
{
SugarDownload *download = (SugarDownload *) g_hash_table_lookup (
download_manager->downloads,
file_name);
g_return_if_fail (download == NULL);
download = g_object_new (SUGAR_TYPE_DOWNLOAD, NULL);
sugar_download_set_url (download, url);
sugar_download_set_mime_type (download, mime_type);
sugar_download_set_file_name (download, file_name);
g_hash_table_insert (download_manager->downloads,
(gpointer)file_name,
download);
g_signal_emit (download_manager, signals[DOWNLOAD_STARTED], 0, download);
}
void
sugar_download_manager_download_completed (SugarDownloadManager *download_manager,
const char *file_name)
{
SugarDownload *download = (SugarDownload *) g_hash_table_lookup (
download_manager->downloads,
file_name);
g_return_if_fail (download);
g_signal_emit (download_manager, signals[DOWNLOAD_COMPLETED], 0, download);
g_hash_table_remove (download_manager->downloads, file_name);
}
void sugar_download_manager_download_cancelled (SugarDownloadManager *download_manager,
const char *file_name)
{
SugarDownload *download = (SugarDownload *) g_hash_table_lookup (
download_manager->downloads,
file_name);
g_return_if_fail (download);
g_signal_emit (download_manager, signals[DOWNLOAD_CANCELLED], 0, download);
g_hash_table_remove (download_manager->downloads, file_name);
}
void
sugar_download_manager_update_progress (SugarDownloadManager *download_manager,
const char *file_name,
const int percent)
{
SugarDownload *download = (SugarDownload *) g_hash_table_lookup (
download_manager->downloads,
file_name);
g_return_if_fail (download);
sugar_download_set_percent (download, percent);
g_signal_emit (download_manager, signals [DOWNLOAD_PROGRESS], 0, download);
}

View File

@ -1,57 +0,0 @@
#ifndef __SUGAR_DOWNLOAD_MANAGER_H__
#define __SUGAR_DOWNLOAD_MANAGER_H__
#include <glib-object.h>
#include <glib.h>
G_BEGIN_DECLS
typedef struct _SugarDownloadManager SugarDownloadManager;
typedef struct _SugarDownloadManagerClass SugarDownloadManagerClass;
#define SUGAR_TYPE_DOWNLOAD_MANAGER (sugar_download_manager_get_type())
#define SUGAR_DOWNLOAD_MANAGER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), SUGAR_TYPE_DOWNLOAD_MANAGER, SugarDownloadManager))
#define SUGAR_DOWNLOAD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SUGAR_TYPE_DOWNLOAD_MANAGER, SugarDownloadManagerClass))
#define SUGAR_IS_DOWNLOAD_MANAGER(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), SUGAR_TYPE_DOWNLOAD_MANAGER))
#define SUGAR_IS_DOWNLOAD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SUGAR_TYPE_DOWNLOAD_MANAGER))
#define SUGAR_DOWNLOAD_MANAGER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), SUGAR_TYPE_DOWNLOAD_MANAGER, SugarDownloadManagerClass))
struct _SugarDownloadManager {
GObject base_instance;
GHashTable *downloads;
};
struct _SugarDownloadManagerClass {
GObjectClass base_class;
void (* handle_content) (char *url, char *tmp_file_name);
};
GType sugar_download_manager_get_type(void);
SugarDownloadManager *sugar_get_download_manager(void);
void sugar_download_manager_download_started(
SugarDownloadManager *download_manager,
const char *url,
const char *mime_type,
const char *tmp_file_name);
void sugar_download_manager_download_completed(
SugarDownloadManager *download_manager,
const char *tmp_file_name);
void sugar_download_manager_download_cancelled(
SugarDownloadManager *download_manager,
const char *tmp_file_name);
void sugar_download_manager_update_progress(
SugarDownloadManager *download_manager,
const char *tmp_file_name,
const int percent);
G_END_DECLS
#endif

View File

@ -1,108 +0,0 @@
#include "sugar-download.h"
static void sugar_download_finalize (GObject *object);
G_DEFINE_TYPE (SugarDownload, sugar_download, G_TYPE_OBJECT)
static void
sugar_download_init (SugarDownload *download)
{
download->file_name = NULL;
download->url = NULL;
download->mime_type = NULL;
download->percent = 0;
}
static void
sugar_download_class_init (SugarDownloadClass *download_class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (download_class);
gobject_class->finalize = sugar_download_finalize;
}
void
sugar_download_set_file_name (SugarDownload *download, const gchar *file_name)
{
gchar *new_file_name;
g_return_if_fail (SUGAR_IS_DOWNLOAD (download));
new_file_name = g_strdup (file_name);
g_free (download->file_name);
download->file_name = new_file_name;
}
void
sugar_download_set_url (SugarDownload *download, const gchar *url)
{
gchar *new_url;
g_return_if_fail (SUGAR_IS_DOWNLOAD (download));
new_url = g_strdup (url);
g_free (download->url);
download->url = new_url;
}
void
sugar_download_set_mime_type (SugarDownload *download, const gchar *mime_type)
{
gchar *new_mime_type;
g_return_if_fail (SUGAR_IS_DOWNLOAD (download));
new_mime_type = g_strdup (mime_type);
g_free (download->mime_type);
download->mime_type = new_mime_type;
}
void
sugar_download_set_percent (SugarDownload *download, const gint percent)
{
g_return_if_fail (SUGAR_IS_DOWNLOAD (download));
download->percent = percent;
}
const gchar *
sugar_download_get_file_name (SugarDownload *download)
{
g_return_val_if_fail (SUGAR_IS_DOWNLOAD (download), NULL);
return download->file_name;
}
const gchar *
sugar_download_get_url (SugarDownload *download)
{
g_return_val_if_fail (SUGAR_IS_DOWNLOAD (download), NULL);
return download->url;
}
const gchar *
sugar_download_get_mime_type (SugarDownload *download)
{
g_return_val_if_fail (SUGAR_IS_DOWNLOAD (download), NULL);
return download->mime_type;
}
gint
sugar_download_get_percent (SugarDownload *download)
{
g_return_val_if_fail (SUGAR_IS_DOWNLOAD (download), -1);
return download->percent;
}
static void
sugar_download_finalize (GObject *object)
{
SugarDownload *download = SUGAR_DOWNLOAD (object);
g_free (download->file_name);
g_free (download->url);
g_free (download->mime_type);
}

View File

@ -1,50 +0,0 @@
#ifndef __SUGAR_DOWNLOAD_H__
#define __SUGAR_DOWNLOAD_H__
#include <glib-object.h>
#include <glib.h>
G_BEGIN_DECLS
typedef struct _SugarDownload SugarDownload;
typedef struct _SugarDownloadClass SugarDownloadClass;
#define SUGAR_TYPE_DOWNLOAD (sugar_download_get_type())
#define SUGAR_DOWNLOAD(object) (G_TYPE_CHECK_INSTANCE_CAST((object), SUGAR_TYPE_DOWNLOAD, SugarDownload))
#define SUGAR_DOWNLOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SUGAR_TYPE_DOWNLOAD, SugarDownloadClass))
#define SUGAR_IS_DOWNLOAD(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), SUGAR_TYPE_DOWNLOAD))
#define SUGAR_IS_DOWNLOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SUGAR_TYPE_DOWNLOAD))
#define SUGAR_DOWNLOAD_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), SUGAR_TYPE_DOWNLOAD, SugarDownloadClass))
struct _SugarDownload {
GObject base_instance;
gchar *file_name;
gchar *url;
gchar *mime_type;
gint percent;
};
struct _SugarDownloadClass {
GObjectClass base_class;
};
GType sugar_download_get_type(void);
void sugar_download_set_file_name (SugarDownload *download,
const gchar *file_name);
void sugar_download_set_url (SugarDownload *download,
const gchar *url);
void sugar_download_set_mime_type (SugarDownload *download,
const gchar *mime_type);
void sugar_download_set_percent (SugarDownload *download,
const gint percent);
const gchar *sugar_download_get_file_name (SugarDownload *download);
const gchar *sugar_download_get_url (SugarDownload *download);
const gchar *sugar_download_get_mime_type (SugarDownload *download);
gint sugar_download_get_percent (SugarDownload *download);
G_END_DECLS
#endif /* __SUGAR_DOWNLOAD_H__ */

View File

@ -1,4 +0,0 @@
VOID:OBJECT,STRING,LONG,LONG
VOID:OBJECT,LONG
VOID:OBJECT
BOOLEAN:BOXED

View File

@ -2,17 +2,11 @@ AC_INIT([Sugar],[0.63],[],[sugar])
AC_PREREQ([2.59])
GNOME_COMMON_INIT
GNOME_COMPILE_WARNINGS
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([configure.ac])
AM_INIT_AUTOMAKE([1.9 foreign dist-bzip2 no-dist-gzip])
AM_MAINTAINER_MODE
AC_DISABLE_STATIC
AC_PROG_LIBTOOL
@ -23,47 +17,14 @@ AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)])
AC_PATH_PROG(PYGTK_CODEGEN, pygtk-codegen-2.0, no)
PKG_CHECK_MODULES(PYGTK, pygtk-2.0)
PKG_CHECK_MODULES(PYCAIRO, pycairo)
PKG_CHECK_MODULES(SHELL, pygtk-2.0 gtk+-2.0 gstreamer-0.10 gstreamer-plugins-base-0.10)
PKG_CHECK_MODULES(LIB, gtk+-2.0)
PKG_CHECK_MODULES(SHELL, gtk+-2.0 gstreamer-0.10 gstreamer-plugins-base-0.10)
PKG_CHECK_MODULES(LIB_BINDINGS, pygtk-2.0)
PYGTK_DEFSDIR=`$PKG_CONFIG --variable=defsdir pygtk-2.0`
AC_SUBST(PYGTK_DEFSDIR)
#
# Mozilla
#
AC_ARG_WITH(libxul_sdk,
AC_HELP_STRING([--with-libxul-sdk=DIR], [Path to libxul SDK]))
if test -d "$with_libxul_sdk"; then
# xulrunner 1.9
GECKO_CFLAGS="-I$with_libxul_sdk/sdk/include -DXPCOM_GLUE"
XPCOMGLUE_LIBS="-L$with_libxul_sdk/sdk/lib -lxpcomglue"
MOZILLA_INCLUDE_DIR="$with_libxul_sdk/include"
XPIDL="$with_libxul_sdk/sdk/bin/xpidl"
MOZILLA_IDL_DIR="$with_libxul_sdk/sdk/idl"
AC_SUBST(XPCOMGLUE_LIBS)
AC_SUBST(GECKO_CFLAGS)
AC_SUBST(MOZILLA_INCLUDE_DIR)
AC_SUBST(XPIDL)
AC_SUBST(MOZILLA_IDL_DIR)
else
AC_MSG_ERROR([Must specify the xulrunner sdk dir (--with-libxul-sdk)])
fi
#
# Setup GETTEXT
#
ALL_LINGUAS="it ha ig yo"
@ -79,10 +40,8 @@ AC_OUTPUT([
Makefile
bin/Makefile
data/Makefile
browser/Makefile
browser/components/Makefile
browser/components/sessionstore/Makefile
browser/components/browserhelper/Makefile
lib/Makefile
lib/xdgmime/Makefile
services/Makefile
services/presence/Makefile
services/clipboard/Makefile
@ -113,10 +72,9 @@ services/console/interface/logviewer/Makefile
services/console/interface/terminal/Makefile
sugar/Makefile
sugar/activity/Makefile
sugar/browser/Makefile
sugar/clipboard/Makefile
sugar/graphics/Makefile
sugar/p2p/Makefile
sugar/objects/Makefile
sugar/presence/Makefile
sugar/datastore/Makefile
po/Makefile.in

View File

@ -8,9 +8,7 @@ sugar-xo.gtkrc: gtkrc.em
sugardir = $(pkgdatadir)/data
sugar_DATA = \
$(GTKRC_FILES) \
gecko-prefs.js \
mime.types
$(GTKRC_FILES)
GTKRC_FILES = \
sugar.gtkrc \

View File

@ -1,97 +0,0 @@
// Disable onload popups
user_pref("dom.disable_open_during_load", true);
// Disable usless security warnings
user_pref("security.warn_entering_secure", false);
user_pref("security.warn_entering_secure.show_once", true);
user_pref("security.warn_leaving_secure", false);
user_pref("security.warn_leaving_secure.show_once", false);
user_pref("security.warn_submit_insecure", false);
user_pref("security.warn_submit_insecure.show_once", false);
user_pref("security.warn_viewing_mixed", true);
user_pref("security.warn_viewing_mixed.show_once", false);
user_pref("security.warn_entering_weak", true);
user_pref("security.warn_entering_weak.show_once", false);
// Set some style properties to not follow our dark gtk theme
user_pref("ui.-moz-field", "#FFFFFF");
user_pref("ui.-moz-fieldtext", "#000000");
user_pref("ui.buttonface", "#D3D3DD");
user_pref("ui.buttontext", "#000000");
// Fonts
user_pref("font.size.unit", "pt");
// Layout:
// 1024x768 -> (96 * 6) / 1024 * 201 = 113 dpi
// 800x600 -> (96 * 6) / 800 * 201 = 144 dpi
//
// Fonts:
// 7 pt -> 7 / 12 * 201 = 117 dpi
// 8 pt -> 8 / 12 * 201 = 134 dpi
// 9 pt -> 9 / 12 * 201 = 150 dpi
user_pref("layout.css.dpi", 134);
user_pref("font.default.ar", "sans-serif");
user_pref("font.size.variable.ar", 12);
user_pref("font.size.fixed.ar", 9);
user_pref("font.default.el", "serif");
user_pref("font.size.variable.el", 12);
user_pref("font.size.fixed.el", 9);
user_pref("font.default.he", "sans-serif");
user_pref("font.size.variable.he", 12);
user_pref("font.size.fixed.he", 9);
user_pref("font.default.ja", "sans-serif");
user_pref("font.size.variable.ja", 12);
user_pref("font.size.fixed.ja", 12);
user_pref("font.default.ko", "sans-serif");
user_pref("font.size.variable.ko", 12);
user_pref("font.size.fixed.ko", 12);
user_pref("font.default.th", "serif");
user_pref("font.size.variable.th", 12);
user_pref("font.size.fixed.th", 9);
user_pref("font.default.tr", "serif");
user_pref("font.size.variable.tr", 12);
user_pref("font.size.fixed.tr", 9);
user_pref("font.default.x-baltic", "serif");
user_pref("font.size.variable.x-baltic", 12);
user_pref("font.size.fixed.x-baltic", 9);
user_pref("font.default.x-central-euro", "serif");
user_pref("font.size.variable.x-central-euro", 12);
user_pref("font.size.fixed.x-central-euro", 9);
user_pref("font.default.x-cyrillic", "serif");
user_pref("font.size.variable.x-cyrillic", 12);
user_pref("font.size.fixed.x-cyrillic", 9);
user_pref("font.default.x-unicode", "serif");
user_pref("font.size.variable.x-unicode", 12);
user_pref("font.size.fixed.x-unicode", 9);
user_pref("font.default.x-western", "serif");
user_pref("font.size.variable.x-western", 12);
user_pref("font.size.fixed.x-western", 9);
user_pref("font.default.zh-CN", "sans-serif");
user_pref("font.size.variable.zh-CN", 12);
user_pref("font.size.fixed.zh-CN", 12);
user_pref("font.default.zh-TW", "sans-serif");
user_pref("font.size.variable.zh-TW", 12);
user_pref("font.size.fixed.zh-TW", 12);
user_pref("font.default.zh-HK", "sans-serif");
user_pref("font.size.variable.zh-HK", 12);
user_pref("font.size.fixed.zh-HK", 12);
// Enable error pages (xulrunner is missing this pref)
user_pref("browser.xul.error_pages.enabled", true);

View File

@ -1,3 +0,0 @@
application/x-squeak-project pr
application/x-abiword abw
application/vnd.olpc-x-sugar xo

14
lib/Makefile.am Normal file
View File

@ -0,0 +1,14 @@
SUBDIRS = xdgmime
libsugar_la_CPPFLAGS = \
$(LIB_CFLAGS)
noinst_LTLIBRARIES = libsugar.la
libsugar_la_LIBADD = \
$(LIB_LIBS) \
$(top_builddir)/lib/xdgmime/libxdgmime.la
libsugar_la_SOURCES = \
sugar-address-entry.c \
sugar-address-entry.h

View File

@ -20,7 +20,7 @@
#ifndef __SUGAR_ADDRESS_ENTRY_H__
#define __SUGAR_ADDRESS_ENTRY_H__
#include <glib-object.h>
#include <gtk/gtkentry.h>
G_BEGIN_DECLS

378
lib/xdgmime/ChangeLog Normal file
View File

@ -0,0 +1,378 @@
2007-01-22 Matthias Clasen <mclasen@redhat.com>
* === 2.10.9 ===
2007-01-17 Matthias Clasen <mclasen@redhat.com>
* === Released 2.10.8 ===
2007-01-07 Matthias Clasen <mclasen@redhat.com>
* xdgmimecache.c (cache_glob_node_lookup_suffix): Don't return ""
as match. (fd.o #9544, Yevgen Muntyan)
2007-01-07 Matthias Clasen <mclasen@redhat.com>
* xdgmimecache.c (_xdg_mime_cache_list_mime_parents): Fix
several problems with this function. (fd.o #9560, Yevgen Muntyan)
2007-01-05 Matthias Clasen <mclasen@redhat.com>
* === Released 2.10.7 ===
2006-10-03 Matthias Clasen <mclasen@redhat.com>
* === Released 2.10.6 ===
2006-10-02 Matthias Clasen <mclasen@redhat.com>
* === Released 2.10.5 ===
2006-09-22 Matthias Clasen <mclasen@redhat.com>
* === Released 2.10.4 ===
2006-09-04 Matthias Clasen <mclasen@redhat.com>
* === Released 2.10.3 ===
2006-08-17 Matthias Clasen <mclasen@redhat.com>
* === Released 2.10.2 ===
2006-07-23 Matthias Clasen <mclasen@redhat.com>
* === Released 2.10.1 ===
2006-07-20 Matthias Clasen <mclasen@redhat.com>
Fix a thinko that leads to constantly reloading
the mime data if a mime.cache is present. Patch
by Yevgen Muntyan, bugs.freedesktop.org #7495
* xdgmime.c (xdg_check_dir): Look for mime.cache first.
(xdg_check_file): Report existance of the file separately.
2006-07-20 Matthias Clasen <mclasen@redhat.com>
* xdgmime.c (xdg_mime_shutdown): Unref the caches.
Patch by Yevgen Muntyan, bugs.freedesktop.org #7496
* xdgmimemagic.c:
* xdgmime.c:
* xdgmime.h: Add xdg_init-free versions of some
functions and use them internally, so that we don't
reload caches and clobber data structures in the
middle of an operation. Patch by Joe Shaw,
bugs.freedesktop.org #6824
2006-07-19 Matthias Clasen <mclasen@redhat.com>
* xdgmimeglob.c (_xdg_glob_hash_node_lookup_file_name):
Don't return NULL as a mimetype, ever, patch
by Yevgen Muntyan, bugs.freedesktop.org #5241
2006-07-02 Matthias Clasen <mclasen@redhat.com>
* === Released 2.10.0 ===
2006-06-21 Matthias Clasen <mclasen@redhat.com>
* === Released 2.9.4 ===
2006-06-12 Matthias Clasen <mclasen@redhat.com>
* === Released 2.9.3 ===
2006-06-05 Matthias Clasen <mclasen@redhat.com>
* === Released 2.9.2 ===
2006-05-16 Matthias Clasen <mclasen@redhat.com>
* === Released 2.9.1 ====
2006-05-04 Matthias Clasen <mclasen@redhat.com>
* === Released 2.9.0 ===
2006-04-03 Matthias Clasen <mclasen@redhat.com>
* xdgmime.[hc]: Move xdg_mime_type_unknown to .rodata.
2006-03-06 Matthias Clasen <mclasen@redhat.com>
* xdgmimemagic.c: Remove superfluous extern errno
declaration. (#333605, Tommi Komulainen)
2006-02-27 Matthias Clasen <mclasen@redhat.com>
* xdgmime.h (xdg_mime_dump): Don't export xdg_mime_dump.
2005-12-01 Matthias Clasen <mclasen@redhat.com>
* Merge upstream changes to handle duplicate glob
patterns.
2005-11-04 Matthias Clasen <mclasen@redhat.com>
* xdgmime.c (xdg_mime_list_mime_parents): Prevent
a segfault.
2005-10-18 Matthias Clasen <mclasen@redhat.com>
* xdgmimecache.c: Make magic comparisons work correctly
in the cache.
2005-10-17 Matthias Clasen <mclasen@redhat.com>
* xdgmime.c (xdg_mime_get_mime_type_for_file): Remove
a debugging printf.
2005-09-01 Matthias Clasen <mclasen@redhat.com>
* xdgmime.h:
* xdgmime.c (xdg_mime_get_mime_type_for_file): Take
a struct statbuf * as argument.
* test-mime.c (main): Adjust.
2005-08-24 Matthias Clasen <mclasen@redhat.com>
* === Released 2.8.2 ===
* === Released 2.8.1 ===
2005-08-13 Matthias Clasen <mclasen@redhat.com>
* === Released 2.8.0 ===
2005-08-07 Matthias Clasen <mclasen@redhat.com>
* Rename caches to _caches, so it doesn't
get exported. Also don't export n_caches.
2005-08-02 Matthias Clasen <mclasen@redhat.com>
* === Released 2.7.5 ===
2005-07-22 Matthias Clasen <mclasen@redhat.com>
* === Released 2.7.4 ===
2005-07-15 Matthias Clasen <mclasen@redhat.com>
* === Released 2.7.3 ===
2005-07-08 Matthias Clasen <mclasen@redhat.com>
* === Released 2.7.2 ===
2005-07-01 Matthias Clasen <mclasen@redhat.com>
* === Released 2.7.1 ===
2005-06-20 Matthias Clasen <mclasen@redhat.com>
* xdgmimecache.c: Handle missing MAP_FAILED. (#308449, Georg
Schwarz)
2005-06-20 Matthias Clasen <mclasen@redhat.com>
* === Released 2.7.0 ===
2005-06-10 Federico Mena Quintero <federico@ximian.com>
* xdgmime.c (xdg_mime_init_from_directory): Pass the correct size
to realloc(). Fixes https://bugs.freedesktop.org/show_bug.cgi?id=3506.
2005-06-09 Matthias Clasen <mclasen@redhat.com>
* xdgmimemagic.c: Don't declare errno, including errno.h
is enough. (#304164, Joerg Sonnenberger)
2005-05-20 Matthias Clasen <mclasen@redhat.com>
* xdgmimecache.c (GET_UINT32): Don't rely on C99
types. (#304924, John Ehresman)
2005-04-29 Matthias Clasen <mclasen@redhat.com>
* Sync to upstream.
2005-04-08 Matthias Clasen <mclasen@redhat.com>
* xdgmimecache.c (cache_magic_matchlet_compare_to_data)
(cache_magic_matchlet_compare): Use cache->buffer, not
cache.
Tue Apr 5 16:00:04 2005 Manish Singh <yosh@gimp.org>
* Makefile.am: add xdgmimecache.[ch].
2005-03-28 Matthias Clasen <mclasen@redhat.com>
* xdgmimeglob.c: Sync to latest upstream,
including fixes for matching against multiple
extensions (eg .tar.gz) and for suffix
patterns which don't start with a dot.
Sat Mar 19 23:52:33 2005 Manish Singh <yosh@gimp.org>
* xdgmimeglob.c (_xdg_glob_hash_insert_text): cast away the constness
in the call to free().
2005-03-20 Matthias Clasen <mclasen@redhat.com>
* xdgmimeglob.c (_xdg_glob_hash_insert_text): Don't
leak node->mime_type if we are reusing an existing
node. (#170774, Kjartan Maraas)
2005-01-08 Matthias Clasen <mclasen@redhat.com>
* === Released 2.6.1 ===
2004-12-16 Matthias Clasen <mclasen@redhat.com>
* === Released 2.6.0 ===
2004-12-13 Marco Pesenti Gritti <marco@gnome.org>
* xdgmimeglob.c: (_xdg_glob_hash_lookup_file_name):
Resync with upstream again
Fri Dec 10 13:58:38 2004 Manish Singh <yosh@gimp.org>
* xdgmime.h: wrap new API in XDG_ENTRY().
2004-12-09 Marco Pesenti Gritti <marco@gnome.org>
* xdgmime.c: (xdg_mime_unalias_mime_type),
(xdg_mime_mime_type_equal), (xdg_mime_mime_type_subclass),
(xdg_mime_get_mime_parents):
* xdgmime.h:
* xdgmimealias.c: (_xdg_mime_alias_list_lookup):
* xdgmimeglob.c: (_xdg_glob_hash_node_lookup_file_name):
* xdgmimeint.c: (_xdg_ucs4_to_lower):
* xdgmimeint.h:
* xdgmimemagic.c: (_xdg_mime_magic_read_from_file):
* xdgmimeparent.c: (_xdg_mime_parent_list_lookup):
Resync with upstream
2004-12-09 Matthias Clasen <mclasen@redhat.com>
* xdgmimealias.c (_xdg_mime_alias_read_from_file):
* xdgmimeparent.c (_xdg_mime_parent_read_from_file): Make
repeated calls accumulate the results, don't call qsort()
on empty arrays. (#160838, Mariano Suárez-Alvarez)
2004-12-02 Matthias Clasen <mclasen@redhat.com>
* === Released 2.5.6 ===
2004-11-29 Matthias Clasen <mclasen@redhat.com>
* xdgmimeparent.c (_xdg_mime_parent_list_lookup):
* xdgmimealias.c (_xdg_mime_alias_list_lookup): Protect
against stupid bsearch() implementations. (#159737,
Morten Welinder)
2004-11-24 Matthias Clasen <mclasen@redhat.com>
* xdgmimeparent.c (_xdg_mime_parent_read_from_file):
Initialize the parent field of the newly allocate list
entry. (#159330, Alex Larsson)
Fri Nov 19 15:10:32 2004 Manish Singh <yosh@gimp.org>
* xdgmime.c: Don't put /* within a comment.
2004-11-09 Matthias Clasen <mclasen@redhat.com>
* xdgmime.h: Prefix all symbols.
2004-11-08 Matthias Clasen <mclasen@redhat.com>
* xdgmime.c (xdg_mime_mime_type_subclass): Enable matching
of supertypes as text/*.
* Sync from upstream
2004-10-27 Matthias Clasen <mclasen@redhat.com>
* === Released 2.5.4 ===
2004-09-19 Matthias Clasen <mclasen@redhat.com>
* === Released 2.5.3 ===
2004-08-25 Matthias Clasen <mclasen@redhat.com>
* === Released 2.5.2 ===
Wed Aug 11 20:44:35 2004 Matthias Clasen <maclas@gmx.de>
* xdgmime.h (xdg_mime_shutdown): Add the XDG_PREFIX to
this function as well.
2004-08-01 Matthias Clasen <mclasen@redhat.com>
* === Released 2.5.1 ===
Tue Jul 20 22:24:35 2004 Matthias Clasen <maclas@gmx.de>
* xdgmimeglob.h: Remove trailing commas from
enumerations. (#148035)
Sun Jul 18 20:17:41 2004 Soeren Sandmann <sandmann@daimi.au.dk>
* === Released 2.5.0 ==
Thu May 27 15:23:17 2004 Jonathan Blandford <jrb@gnome.org>
* Sync from upstream
Fri Apr 30 00:19:11 2004 Matthias Clasen <maclas@gmx.de>
* xdgmimemagic.c (_xdg_mime_magic_read_a_number): Make sure
the static string is long enough. (#136323, Morten Welinder)
2004-03-12 Morten Welinder <terra@gnome.org>
* *.c: Make sure to include <config.h> (#137001)
Wed Mar 10 22:48:15 2004 Jonathan Blandford <jrb@gnome.org>
* Sync from upstream
Sun Feb 8 19:05:16 2004 Manish Singh <yosh@gimp.org>
* xdgmimeint.h: declare _xdg_utf8_skip as extern to prevent multiple
definitions.
Wed Jan 21 09:33:13 2004 Jonathan Blandford <jrb@gnome.org>
* libgnomevfs/xdgmimeglob.c:
* libgnomevfs/xdgmimemagic.c: Sync from upstream
Tue Jan 20 13:07:04 2004 Jonathan Blandford <jrb@gnome.org>
* xdgmime.c: resync with upstream sources.
Fri Oct 24 16:54:57 2003 Owen Taylor <otaylor@redhat.com>
* Makefile.am (libxdgmime_la_SOURCES): Add .h files to
SOURCES.
Fri Oct 24 16:02:32 2003 Owen Taylor <otaylor@redhat.com>
* *.[ch]: Relicense to be dual AFL/LGPL (and thus also
GPL) rather than AFL/GPL. Also update AFL version to 1.2.
Tue Jul 22 15:37:45 2003 Jonathan Blandford <jrb@gnome.org>
* xdgmime/xdgmime.c (xdg_mime_init): use XDG_DATA_HOME instead of
XDG_CONFIG_HOME.

19
lib/xdgmime/Makefile.am Normal file
View File

@ -0,0 +1,19 @@
INCLUDES = -DXDG_PREFIX=sugar_mime
noinst_LTLIBRARIES = libxdgmime.la
libxdgmime_la_SOURCES = \
xdgmime.c \
xdgmime.h \
xdgmimealias.c \
xdgmimealias.h \
xdgmimecache.c \
xdgmimecache.h \
xdgmimeglob.c \
xdgmimeglob.h \
xdgmimeint.c \
xdgmimeint.h \
xdgmimemagic.c \
xdgmimemagic.h \
xdgmimeparent.c \
xdgmimeparent.h

850
lib/xdgmime/xdgmime.c Normal file
View File

@ -0,0 +1,850 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmime.c: XDG Mime Spec mime resolver. Based on version 0.11 of the spec.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2003,2004 Red Hat, Inc.
* Copyright (C) 2003,2004 Jonathan Blandford <jrb@alum.mit.edu>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "xdgmime.h"
#include "xdgmimeint.h"
#include "xdgmimeglob.h"
#include "xdgmimemagic.h"
#include "xdgmimealias.h"
#include "xdgmimeparent.h"
#include "xdgmimecache.h"
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
typedef struct XdgDirTimeList XdgDirTimeList;
typedef struct XdgCallbackList XdgCallbackList;
static int need_reread = TRUE;
static time_t last_stat_time = 0;
static XdgGlobHash *global_hash = NULL;
static XdgMimeMagic *global_magic = NULL;
static XdgAliasList *alias_list = NULL;
static XdgParentList *parent_list = NULL;
static XdgDirTimeList *dir_time_list = NULL;
static XdgCallbackList *callback_list = NULL;
XdgMimeCache **_caches = NULL;
static int n_caches = 0;
const char xdg_mime_type_unknown[] = "application/octet-stream";
enum
{
XDG_CHECKED_UNCHECKED,
XDG_CHECKED_VALID,
XDG_CHECKED_INVALID
};
struct XdgDirTimeList
{
time_t mtime;
char *directory_name;
int checked;
XdgDirTimeList *next;
};
struct XdgCallbackList
{
XdgCallbackList *next;
XdgCallbackList *prev;
int callback_id;
XdgMimeCallback callback;
void *data;
XdgMimeDestroy destroy;
};
/* Function called by xdg_run_command_on_dirs. If it returns TRUE, further
* directories aren't looked at */
typedef int (*XdgDirectoryFunc) (const char *directory,
void *user_data);
static XdgDirTimeList *
xdg_dir_time_list_new (void)
{
XdgDirTimeList *retval;
retval = calloc (1, sizeof (XdgDirTimeList));
retval->checked = XDG_CHECKED_UNCHECKED;
return retval;
}
static void
xdg_dir_time_list_free (XdgDirTimeList *list)
{
XdgDirTimeList *next;
while (list)
{
next = list->next;
free (list->directory_name);
free (list);
list = next;
}
}
static int
xdg_mime_init_from_directory (const char *directory)
{
char *file_name;
struct stat st;
XdgDirTimeList *list;
assert (directory != NULL);
file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
if (stat (file_name, &st) == 0)
{
XdgMimeCache *cache = _xdg_mime_cache_new_from_file (file_name);
if (cache != NULL)
{
list = xdg_dir_time_list_new ();
list->directory_name = file_name;
list->mtime = st.st_mtime;
list->next = dir_time_list;
dir_time_list = list;
_caches = realloc (_caches, sizeof (XdgMimeCache *) * (n_caches + 2));
_caches[n_caches] = cache;
_caches[n_caches + 1] = NULL;
n_caches++;
return FALSE;
}
}
free (file_name);
file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/globs");
if (stat (file_name, &st) == 0)
{
_xdg_mime_glob_read_from_file (global_hash, file_name);
list = xdg_dir_time_list_new ();
list->directory_name = file_name;
list->mtime = st.st_mtime;
list->next = dir_time_list;
dir_time_list = list;
}
else
{
free (file_name);
}
file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/magic");
if (stat (file_name, &st) == 0)
{
_xdg_mime_magic_read_from_file (global_magic, file_name);
list = xdg_dir_time_list_new ();
list->directory_name = file_name;
list->mtime = st.st_mtime;
list->next = dir_time_list;
dir_time_list = list;
}
else
{
free (file_name);
}
file_name = malloc (strlen (directory) + strlen ("/mime/aliases") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/aliases");
_xdg_mime_alias_read_from_file (alias_list, file_name);
free (file_name);
file_name = malloc (strlen (directory) + strlen ("/mime/subclasses") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/subclasses");
_xdg_mime_parent_read_from_file (parent_list, file_name);
free (file_name);
return FALSE; /* Keep processing */
}
/* Runs a command on all the directories in the search path */
static void
xdg_run_command_on_dirs (XdgDirectoryFunc func,
void *user_data)
{
const char *xdg_data_home;
const char *xdg_data_dirs;
const char *ptr;
xdg_data_home = getenv ("XDG_DATA_HOME");
if (xdg_data_home)
{
if ((func) (xdg_data_home, user_data))
return;
}
else
{
const char *home;
home = getenv ("HOME");
if (home != NULL)
{
char *guessed_xdg_home;
int stop_processing;
guessed_xdg_home = malloc (strlen (home) + strlen ("/.local/share/") + 1);
strcpy (guessed_xdg_home, home);
strcat (guessed_xdg_home, "/.local/share/");
stop_processing = (func) (guessed_xdg_home, user_data);
free (guessed_xdg_home);
if (stop_processing)
return;
}
}
xdg_data_dirs = getenv ("XDG_DATA_DIRS");
if (xdg_data_dirs == NULL)
xdg_data_dirs = "/usr/local/share/:/usr/share/";
ptr = xdg_data_dirs;
while (*ptr != '\000')
{
const char *end_ptr;
char *dir;
int len;
int stop_processing;
end_ptr = ptr;
while (*end_ptr != ':' && *end_ptr != '\000')
end_ptr ++;
if (end_ptr == ptr)
{
ptr++;
continue;
}
if (*end_ptr == ':')
len = end_ptr - ptr;
else
len = end_ptr - ptr + 1;
dir = malloc (len + 1);
strncpy (dir, ptr, len);
dir[len] = '\0';
stop_processing = (func) (dir, user_data);
free (dir);
if (stop_processing)
return;
ptr = end_ptr;
}
}
/* Checks file_path to make sure it has the same mtime as last time it was
* checked. If it has a different mtime, or if the file doesn't exist, it
* returns FALSE.
*
* FIXME: This doesn't protect against permission changes.
*/
static int
xdg_check_file (const char *file_path,
int *exists)
{
struct stat st;
/* If the file exists */
if (stat (file_path, &st) == 0)
{
XdgDirTimeList *list;
if (exists)
*exists = TRUE;
for (list = dir_time_list; list; list = list->next)
{
if (! strcmp (list->directory_name, file_path) &&
st.st_mtime == list->mtime)
{
if (list->checked == XDG_CHECKED_UNCHECKED)
list->checked = XDG_CHECKED_VALID;
else if (list->checked == XDG_CHECKED_VALID)
list->checked = XDG_CHECKED_INVALID;
return (list->checked != XDG_CHECKED_VALID);
}
}
return TRUE;
}
if (exists)
*exists = FALSE;
return FALSE;
}
static int
xdg_check_dir (const char *directory,
int *invalid_dir_list)
{
int invalid, exists;
char *file_name;
assert (directory != NULL);
/* Check the mime.cache file */
file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
invalid = xdg_check_file (file_name, &exists);
free (file_name);
if (invalid)
{
*invalid_dir_list = TRUE;
return TRUE;
}
else if (exists)
{
return FALSE;
}
/* Check the globs file */
file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/globs");
invalid = xdg_check_file (file_name, NULL);
free (file_name);
if (invalid)
{
*invalid_dir_list = TRUE;
return TRUE;
}
/* Check the magic file */
file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
strcpy (file_name, directory); strcat (file_name, "/mime/magic");
invalid = xdg_check_file (file_name, NULL);
free (file_name);
if (invalid)
{
*invalid_dir_list = TRUE;
return TRUE;
}
return FALSE; /* Keep processing */
}
/* Walks through all the mime files stat()ing them to see if they've changed.
* Returns TRUE if they have. */
static int
xdg_check_dirs (void)
{
XdgDirTimeList *list;
int invalid_dir_list = FALSE;
for (list = dir_time_list; list; list = list->next)
list->checked = XDG_CHECKED_UNCHECKED;
xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_check_dir,
&invalid_dir_list);
if (invalid_dir_list)
return TRUE;
for (list = dir_time_list; list; list = list->next)
{
if (list->checked != XDG_CHECKED_VALID)
return TRUE;
}
return FALSE;
}
/* We want to avoid stat()ing on every single mime call, so we only look for
* newer files every 5 seconds. This will return TRUE if we need to reread the
* mime data from disk.
*/
static int
xdg_check_time_and_dirs (void)
{
struct timeval tv;
time_t current_time;
int retval = FALSE;
gettimeofday (&tv, NULL);
current_time = tv.tv_sec;
if (current_time >= last_stat_time + 5)
{
retval = xdg_check_dirs ();
last_stat_time = current_time;
}
return retval;
}
/* Called in every public function. It reloads the hash function if need be.
*/
static void
xdg_mime_init (void)
{
if (xdg_check_time_and_dirs ())
{
xdg_mime_shutdown ();
}
if (need_reread)
{
global_hash = _xdg_glob_hash_new ();
global_magic = _xdg_mime_magic_new ();
alias_list = _xdg_mime_alias_list_new ();
parent_list = _xdg_mime_parent_list_new ();
xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_mime_init_from_directory,
NULL);
need_reread = FALSE;
}
}
const char *
xdg_mime_get_mime_type_for_data (const void *data,
size_t len)
{
const char *mime_type;
xdg_mime_init ();
if (_caches)
return _xdg_mime_cache_get_mime_type_for_data (data, len);
mime_type = _xdg_mime_magic_lookup_data (global_magic, data, len, NULL, 0);
if (mime_type)
return mime_type;
return XDG_MIME_TYPE_UNKNOWN;
}
const char *
xdg_mime_get_mime_type_for_file (const char *file_name,
struct stat *statbuf)
{
const char *mime_type;
/* currently, only a few globs occur twice, and none
* more often, so 5 seems plenty.
*/
const char *mime_types[5];
FILE *file;
unsigned char *data;
int max_extent;
int bytes_read;
struct stat buf;
const char *base_name;
int n;
if (file_name == NULL)
return NULL;
if (! _xdg_utf8_validate (file_name))
return NULL;
xdg_mime_init ();
if (_caches)
return _xdg_mime_cache_get_mime_type_for_file (file_name, statbuf);
base_name = _xdg_get_base_name (file_name);
n = _xdg_glob_hash_lookup_file_name (global_hash, base_name, mime_types, 5);
if (n == 1)
return mime_types[0];
if (!statbuf)
{
if (stat (file_name, &buf) != 0)
return XDG_MIME_TYPE_UNKNOWN;
statbuf = &buf;
}
if (!S_ISREG (statbuf->st_mode))
return XDG_MIME_TYPE_UNKNOWN;
/* FIXME: Need to make sure that max_extent isn't totally broken. This could
* be large and need getting from a stream instead of just reading it all
* in. */
max_extent = _xdg_mime_magic_get_buffer_extents (global_magic);
data = malloc (max_extent);
if (data == NULL)
return XDG_MIME_TYPE_UNKNOWN;
file = fopen (file_name, "r");
if (file == NULL)
{
free (data);
return XDG_MIME_TYPE_UNKNOWN;
}
bytes_read = fread (data, 1, max_extent, file);
if (ferror (file))
{
free (data);
fclose (file);
return XDG_MIME_TYPE_UNKNOWN;
}
mime_type = _xdg_mime_magic_lookup_data (global_magic, data, bytes_read,
mime_types, n);
free (data);
fclose (file);
if (mime_type)
return mime_type;
return XDG_MIME_TYPE_UNKNOWN;
}
const char *
xdg_mime_get_mime_type_from_file_name (const char *file_name)
{
const char *mime_type;
xdg_mime_init ();
if (_caches)
return _xdg_mime_cache_get_mime_type_from_file_name (file_name);
if (_xdg_glob_hash_lookup_file_name (global_hash, file_name, &mime_type, 1))
return mime_type;
else
return XDG_MIME_TYPE_UNKNOWN;
}
int
xdg_mime_is_valid_mime_type (const char *mime_type)
{
/* FIXME: We should make this a better test
*/
return _xdg_utf8_validate (mime_type);
}
void
xdg_mime_shutdown (void)
{
XdgCallbackList *list;
/* FIXME: Need to make this (and the whole library) thread safe */
if (dir_time_list)
{
xdg_dir_time_list_free (dir_time_list);
dir_time_list = NULL;
}
if (global_hash)
{
_xdg_glob_hash_free (global_hash);
global_hash = NULL;
}
if (global_magic)
{
_xdg_mime_magic_free (global_magic);
global_magic = NULL;
}
if (alias_list)
{
_xdg_mime_alias_list_free (alias_list);
alias_list = NULL;
}
if (parent_list)
{
_xdg_mime_parent_list_free (parent_list);
parent_list = NULL;
}
if (_caches)
{
int i;
for (i = 0; i < n_caches; i++)
_xdg_mime_cache_unref (_caches[i]);
free (_caches);
_caches = NULL;
n_caches = 0;
}
for (list = callback_list; list; list = list->next)
(list->callback) (list->data);
need_reread = TRUE;
}
int
xdg_mime_get_max_buffer_extents (void)
{
xdg_mime_init ();
if (_caches)
return _xdg_mime_cache_get_max_buffer_extents ();
return _xdg_mime_magic_get_buffer_extents (global_magic);
}
const char *
_xdg_mime_unalias_mime_type (const char *mime_type)
{
const char *lookup;
if (_caches)
return _xdg_mime_cache_unalias_mime_type (mime_type);
if ((lookup = _xdg_mime_alias_list_lookup (alias_list, mime_type)) != NULL)
return lookup;
return mime_type;
}
const char *
xdg_mime_unalias_mime_type (const char *mime_type)
{
xdg_mime_init ();
return _xdg_mime_unalias_mime_type (mime_type);
}
int
_xdg_mime_mime_type_equal (const char *mime_a,
const char *mime_b)
{
const char *unalias_a, *unalias_b;
unalias_a = _xdg_mime_unalias_mime_type (mime_a);
unalias_b = _xdg_mime_unalias_mime_type (mime_b);
if (strcmp (unalias_a, unalias_b) == 0)
return 1;
return 0;
}
int
xdg_mime_mime_type_equal (const char *mime_a,
const char *mime_b)
{
xdg_mime_init ();
return _xdg_mime_mime_type_equal (mime_a, mime_b);
}
int
xdg_mime_media_type_equal (const char *mime_a,
const char *mime_b)
{
char *sep;
xdg_mime_init ();
sep = strchr (mime_a, '/');
if (sep && strncmp (mime_a, mime_b, sep - mime_a + 1) == 0)
return 1;
return 0;
}
#if 1
static int
xdg_mime_is_super_type (const char *mime)
{
int length;
const char *type;
length = strlen (mime);
type = &(mime[length - 2]);
if (strcmp (type, "/*") == 0)
return 1;
return 0;
}
#endif
int
_xdg_mime_mime_type_subclass (const char *mime,
const char *base)
{
const char *umime, *ubase;
const char **parents;
if (_caches)
return _xdg_mime_cache_mime_type_subclass (mime, base);
umime = _xdg_mime_unalias_mime_type (mime);
ubase = _xdg_mime_unalias_mime_type (base);
if (strcmp (umime, ubase) == 0)
return 1;
#if 1
/* Handle supertypes */
if (xdg_mime_is_super_type (ubase) &&
xdg_mime_media_type_equal (umime, ubase))
return 1;
#endif
/* Handle special cases text/plain and application/octet-stream */
if (strcmp (ubase, "text/plain") == 0 &&
strncmp (umime, "text/", 5) == 0)
return 1;
if (strcmp (ubase, "application/octet-stream") == 0)
return 1;
parents = _xdg_mime_parent_list_lookup (parent_list, umime);
for (; parents && *parents; parents++)
{
if (_xdg_mime_mime_type_subclass (*parents, ubase))
return 1;
}
return 0;
}
int
xdg_mime_mime_type_subclass (const char *mime,
const char *base)
{
xdg_mime_init ();
return _xdg_mime_mime_type_subclass (mime, base);
}
char **
xdg_mime_list_mime_parents (const char *mime)
{
const char **parents;
char **result;
int i, n;
if (_caches)
return _xdg_mime_cache_list_mime_parents (mime);
parents = xdg_mime_get_mime_parents (mime);
if (!parents)
return NULL;
for (i = 0; parents[i]; i++) ;
n = (i + 1) * sizeof (char *);
result = (char **) malloc (n);
memcpy (result, parents, n);
return result;
}
const char **
xdg_mime_get_mime_parents (const char *mime)
{
const char *umime;
xdg_mime_init ();
umime = _xdg_mime_unalias_mime_type (mime);
return _xdg_mime_parent_list_lookup (parent_list, umime);
}
void
xdg_mime_dump (void)
{
printf ("*** ALIASES ***\n\n");
_xdg_mime_alias_list_dump (alias_list);
printf ("\n*** PARENTS ***\n\n");
_xdg_mime_parent_list_dump (parent_list);
}
/* Registers a function to be called every time the mime database reloads its files
*/
int
xdg_mime_register_reload_callback (XdgMimeCallback callback,
void *data,
XdgMimeDestroy destroy)
{
XdgCallbackList *list_el;
static int callback_id = 1;
/* Make a new list element */
list_el = calloc (1, sizeof (XdgCallbackList));
list_el->callback_id = callback_id;
list_el->callback = callback;
list_el->data = data;
list_el->destroy = destroy;
list_el->next = callback_list;
if (list_el->next)
list_el->next->prev = list_el;
callback_list = list_el;
callback_id ++;
return callback_id - 1;
}
void
xdg_mime_remove_callback (int callback_id)
{
XdgCallbackList *list;
for (list = callback_list; list; list = list->next)
{
if (list->callback_id == callback_id)
{
if (list->next)
list->next = list->prev;
if (list->prev)
list->prev->next = list->next;
else
callback_list = list->next;
/* invoke the destroy handler */
(list->destroy) (list->data);
free (list);
return;
}
}
}

111
lib/xdgmime/xdgmime.h Normal file
View File

@ -0,0 +1,111 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmime.h: XDG Mime Spec mime resolver. Based on version 0.11 of the spec.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2003 Red Hat, Inc.
* Copyright (C) 2003 Jonathan Blandford <jrb@alum.mit.edu>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __XDG_MIME_H__
#define __XDG_MIME_H__
#include <stdlib.h>
#include <sys/stat.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifdef XDG_PREFIX
#define XDG_ENTRY(func) _XDG_ENTRY2(XDG_PREFIX,func)
#define _XDG_ENTRY2(prefix,func) _XDG_ENTRY3(prefix,func)
#define _XDG_ENTRY3(prefix,func) prefix##_##func
#endif
typedef void (*XdgMimeCallback) (void *user_data);
typedef void (*XdgMimeDestroy) (void *user_data);
#ifdef XDG_PREFIX
#define xdg_mime_get_mime_type_for_data XDG_ENTRY(get_mime_type_for_data)
#define xdg_mime_get_mime_type_for_file XDG_ENTRY(get_mime_type_for_file)
#define xdg_mime_get_mime_type_from_file_name XDG_ENTRY(get_mime_type_from_file_name)
#define xdg_mime_is_valid_mime_type XDG_ENTRY(is_valid_mime_type)
#define xdg_mime_mime_type_equal XDG_ENTRY(mime_type_equal)
#define xdg_mime_media_type_equal XDG_ENTRY(media_type_equal)
#define xdg_mime_mime_type_subclass XDG_ENTRY(mime_type_subclass)
#define xdg_mime_get_mime_parents XDG_ENTRY(get_mime_parents)
#define xdg_mime_list_mime_parents XDG_ENTRY(list_mime_parents)
#define xdg_mime_unalias_mime_type XDG_ENTRY(unalias_mime_type)
#define xdg_mime_get_max_buffer_extents XDG_ENTRY(get_max_buffer_extents)
#define xdg_mime_shutdown XDG_ENTRY(shutdown)
#define xdg_mime_dump XDG_ENTRY(dump)
#define xdg_mime_register_reload_callback XDG_ENTRY(register_reload_callback)
#define xdg_mime_remove_callback XDG_ENTRY(remove_callback)
#define xdg_mime_type_unknown XDG_ENTRY(type_unknown)
#endif
extern const char xdg_mime_type_unknown[];
#define XDG_MIME_TYPE_UNKNOWN xdg_mime_type_unknown
const char *xdg_mime_get_mime_type_for_data (const void *data,
size_t len);
const char *xdg_mime_get_mime_type_for_file (const char *file_name,
struct stat *statbuf);
const char *xdg_mime_get_mime_type_from_file_name (const char *file_name);
int xdg_mime_is_valid_mime_type (const char *mime_type);
int xdg_mime_mime_type_equal (const char *mime_a,
const char *mime_b);
int xdg_mime_media_type_equal (const char *mime_a,
const char *mime_b);
int xdg_mime_mime_type_subclass (const char *mime_a,
const char *mime_b);
/* xdg_mime_get_mime_parents() is deprecated since it does
* not work correctly with caches. Use xdg_mime_list_parents()
* instead, but notice that that function expects you to free
* the array it returns.
*/
const char **xdg_mime_get_mime_parents (const char *mime);
char ** xdg_mime_list_mime_parents (const char *mime);
const char *xdg_mime_unalias_mime_type (const char *mime);
int xdg_mime_get_max_buffer_extents (void);
void xdg_mime_shutdown (void);
void xdg_mime_dump (void);
int xdg_mime_register_reload_callback (XdgMimeCallback callback,
void *data,
XdgMimeDestroy destroy);
void xdg_mime_remove_callback (int callback_id);
/* Private versions of functions that don't call xdg_mime_init () */
int _xdg_mime_mime_type_equal (const char *mime_a,
const char *mime_b);
int _xdg_mime_media_type_equal (const char *mime_a,
const char *mime_b);
int _xdg_mime_mime_type_subclass (const char *mime,
const char *base);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __XDG_MIME_H__ */

184
lib/xdgmime/xdgmimealias.c Normal file
View File

@ -0,0 +1,184 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmimealias.c: Private file. Datastructure for storing the aliases.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2004 Red Hat, Inc.
* Copyright (C) 2004 Matthias Clasen <mclasen@redhat.com>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "xdgmimealias.h"
#include "xdgmimeint.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <fnmatch.h>
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
typedef struct XdgAlias XdgAlias;
struct XdgAlias
{
char *alias;
char *mime_type;
};
struct XdgAliasList
{
struct XdgAlias *aliases;
int n_aliases;
};
XdgAliasList *
_xdg_mime_alias_list_new (void)
{
XdgAliasList *list;
list = malloc (sizeof (XdgAliasList));
list->aliases = NULL;
list->n_aliases = 0;
return list;
}
void
_xdg_mime_alias_list_free (XdgAliasList *list)
{
int i;
if (list->aliases)
{
for (i = 0; i < list->n_aliases; i++)
{
free (list->aliases[i].alias);
free (list->aliases[i].mime_type);
}
free (list->aliases);
}
free (list);
}
static int
alias_entry_cmp (const void *v1, const void *v2)
{
return strcmp (((XdgAlias *)v1)->alias, ((XdgAlias *)v2)->alias);
}
const char *
_xdg_mime_alias_list_lookup (XdgAliasList *list,
const char *alias)
{
XdgAlias *entry;
XdgAlias key;
if (list->n_aliases > 0)
{
key.alias = (char *)alias;
key.mime_type = 0;
entry = bsearch (&key, list->aliases, list->n_aliases,
sizeof (XdgAlias), alias_entry_cmp);
if (entry)
return entry->mime_type;
}
return NULL;
}
void
_xdg_mime_alias_read_from_file (XdgAliasList *list,
const char *file_name)
{
FILE *file;
char line[255];
int alloc;
file = fopen (file_name, "r");
if (file == NULL)
return;
/* FIXME: Not UTF-8 safe. Doesn't work if lines are greater than 255 chars.
* Blah */
alloc = list->n_aliases + 16;
list->aliases = realloc (list->aliases, alloc * sizeof (XdgAlias));
while (fgets (line, 255, file) != NULL)
{
char *sep;
if (line[0] == '#')
continue;
sep = strchr (line, ' ');
if (sep == NULL)
continue;
*(sep++) = '\000';
sep[strlen (sep) -1] = '\000';
if (list->n_aliases == alloc)
{
alloc <<= 1;
list->aliases = realloc (list->aliases,
alloc * sizeof (XdgAlias));
}
list->aliases[list->n_aliases].alias = strdup (line);
list->aliases[list->n_aliases].mime_type = strdup (sep);
list->n_aliases++;
}
list->aliases = realloc (list->aliases,
list->n_aliases * sizeof (XdgAlias));
fclose (file);
if (list->n_aliases > 1)
qsort (list->aliases, list->n_aliases,
sizeof (XdgAlias), alias_entry_cmp);
}
void
_xdg_mime_alias_list_dump (XdgAliasList *list)
{
int i;
if (list->aliases)
{
for (i = 0; i < list->n_aliases; i++)
{
printf ("%s %s\n",
list->aliases[i].alias,
list->aliases[i].mime_type);
}
}
}

View File

@ -0,0 +1,50 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmimealias.h: Private file. Datastructure for storing the aliases.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2004 Red Hat, Inc.
* Copyright (C) 200 Matthias Clasen <mclasen@redhat.com>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __XDG_MIME_ALIAS_H__
#define __XDG_MIME_ALIAS_H__
#include "xdgmime.h"
typedef struct XdgAliasList XdgAliasList;
#ifdef XDG_PREFIX
#define _xdg_mime_alias_read_from_file XDG_ENTRY(alias_read_from_file)
#define _xdg_mime_alias_list_new XDG_ENTRY(alias_list_new)
#define _xdg_mime_alias_list_free XDG_ENTRY(alias_list_free)
#define _xdg_mime_alias_list_lookup XDG_ENTRY(alias_list_lookup)
#endif
void _xdg_mime_alias_read_from_file (XdgAliasList *list,
const char *file_name);
XdgAliasList *_xdg_mime_alias_list_new (void);
void _xdg_mime_alias_list_free (XdgAliasList *list);
const char *_xdg_mime_alias_list_lookup (XdgAliasList *list,
const char *alias);
void _xdg_mime_alias_list_dump (XdgAliasList *list);
#endif /* __XDG_MIME_ALIAS_H__ */

895
lib/xdgmime/xdgmimecache.c Normal file
View File

@ -0,0 +1,895 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmimealias.c: Private file. mmappable caches for mime data
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2005 Matthias Clasen <mclasen@redhat.com>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <fnmatch.h>
#include <assert.h>
#include <netinet/in.h> /* for ntohl/ntohs */
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#include "xdgmimecache.h"
#include "xdgmimeint.h"
#ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
#ifndef _O_BINARY
#define _O_BINARY 0
#endif
#ifndef MAP_FAILED
#define MAP_FAILED ((void *) -1)
#endif
#define MAJOR_VERSION 1
#define MINOR_VERSION 0
struct _XdgMimeCache
{
int ref_count;
size_t size;
char *buffer;
};
#define GET_UINT16(cache,offset) (ntohs(*(xdg_uint16_t*)((cache) + (offset))))
#define GET_UINT32(cache,offset) (ntohl(*(xdg_uint32_t*)((cache) + (offset))))
XdgMimeCache *
_xdg_mime_cache_ref (XdgMimeCache *cache)
{
cache->ref_count++;
return cache;
}
void
_xdg_mime_cache_unref (XdgMimeCache *cache)
{
cache->ref_count--;
if (cache->ref_count == 0)
{
#ifdef HAVE_MMAP
munmap (cache->buffer, cache->size);
#endif
free (cache);
}
}
XdgMimeCache *
_xdg_mime_cache_new_from_file (const char *file_name)
{
XdgMimeCache *cache = NULL;
#ifdef HAVE_MMAP
int fd = -1;
struct stat st;
char *buffer = NULL;
/* Open the file and map it into memory */
fd = open (file_name, O_RDONLY|_O_BINARY, 0);
if (fd < 0)
return NULL;
if (fstat (fd, &st) < 0 || st.st_size < 4)
goto done;
buffer = (char *) mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (buffer == MAP_FAILED)
goto done;
/* Verify version */
if (GET_UINT16 (buffer, 0) != MAJOR_VERSION ||
GET_UINT16 (buffer, 2) != MINOR_VERSION)
{
munmap (buffer, st.st_size);
goto done;
}
cache = (XdgMimeCache *) malloc (sizeof (XdgMimeCache));
cache->ref_count = 1;
cache->buffer = buffer;
cache->size = st.st_size;
done:
if (fd != -1)
close (fd);
#endif /* HAVE_MMAP */
return cache;
}
static int
cache_magic_matchlet_compare_to_data (XdgMimeCache *cache,
xdg_uint32_t offset,
const void *data,
size_t len)
{
xdg_uint32_t range_start = GET_UINT32 (cache->buffer, offset);
xdg_uint32_t range_length = GET_UINT32 (cache->buffer, offset + 4);
xdg_uint32_t data_length = GET_UINT32 (cache->buffer, offset + 12);
xdg_uint32_t data_offset = GET_UINT32 (cache->buffer, offset + 16);
xdg_uint32_t mask_offset = GET_UINT32 (cache->buffer, offset + 20);
int i, j;
for (i = range_start; i <= range_start + range_length; i++)
{
int valid_matchlet = TRUE;
if (i + data_length > len)
return FALSE;
if (mask_offset)
{
for (j = 0; j < data_length; j++)
{
if ((((unsigned char *)cache->buffer)[data_offset + j] & ((unsigned char *)cache->buffer)[mask_offset + j]) !=
((((unsigned char *) data)[j + i]) & ((unsigned char *)cache->buffer)[mask_offset + j]))
{
valid_matchlet = FALSE;
break;
}
}
}
else
{
for (j = 0; j < data_length; j++)
{
if (((unsigned char *)cache->buffer)[data_offset + j] != ((unsigned char *) data)[j + i])
{
valid_matchlet = FALSE;
break;
}
}
}
if (valid_matchlet)
return TRUE;
}
return FALSE;
}
static int
cache_magic_matchlet_compare (XdgMimeCache *cache,
xdg_uint32_t offset,
const void *data,
size_t len)
{
xdg_uint32_t n_children = GET_UINT32 (cache->buffer, offset + 24);
xdg_uint32_t child_offset = GET_UINT32 (cache->buffer, offset + 28);
int i;
if (cache_magic_matchlet_compare_to_data (cache, offset, data, len))
{
if (n_children == 0)
return TRUE;
for (i = 0; i < n_children; i++)
{
if (cache_magic_matchlet_compare (cache, child_offset + 32 * i,
data, len))
return TRUE;
}
}
return FALSE;
}
static const char *
cache_magic_compare_to_data (XdgMimeCache *cache,
xdg_uint32_t offset,
const void *data,
size_t len,
int *prio)
{
xdg_uint32_t priority = GET_UINT32 (cache->buffer, offset);
xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, offset + 4);
xdg_uint32_t n_matchlets = GET_UINT32 (cache->buffer, offset + 8);
xdg_uint32_t matchlet_offset = GET_UINT32 (cache->buffer, offset + 12);
int i;
for (i = 0; i < n_matchlets; i++)
{
if (cache_magic_matchlet_compare (cache, matchlet_offset + i * 32,
data, len))
{
*prio = priority;
return cache->buffer + mimetype_offset;
}
}
return NULL;
}
static const char *
cache_magic_lookup_data (XdgMimeCache *cache,
const void *data,
size_t len,
int *prio,
const char *mime_types[],
int n_mime_types)
{
xdg_uint32_t list_offset;
xdg_uint32_t n_entries;
xdg_uint32_t offset;
int j, n;
*prio = 0;
list_offset = GET_UINT32 (cache->buffer, 24);
n_entries = GET_UINT32 (cache->buffer, list_offset);
offset = GET_UINT32 (cache->buffer, list_offset + 8);
for (j = 0; j < n_entries; j++)
{
const char *match;
match = cache_magic_compare_to_data (cache, offset + 16 * j,
data, len, prio);
if (match)
return match;
else
{
xdg_uint32_t mimetype_offset;
const char *non_match;
mimetype_offset = GET_UINT32 (cache->buffer, offset + 16 * j + 4);
non_match = cache->buffer + mimetype_offset;
for (n = 0; n < n_mime_types; n++)
{
if (mime_types[n] &&
xdg_mime_mime_type_equal (mime_types[n], non_match))
mime_types[n] = NULL;
}
}
}
return NULL;
}
static const char *
cache_alias_lookup (const char *alias)
{
const char *ptr;
int i, min, max, mid, cmp;
for (i = 0; _caches[i]; i++)
{
XdgMimeCache *cache = _caches[i];
xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 4);
xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
xdg_uint32_t offset;
min = 0;
max = n_entries - 1;
while (max >= min)
{
mid = (min + max) / 2;
offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid);
ptr = cache->buffer + offset;
cmp = strcmp (ptr, alias);
if (cmp < 0)
min = mid + 1;
else if (cmp > 0)
max = mid - 1;
else
{
offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid + 4);
return cache->buffer + offset;
}
}
}
return NULL;
}
static int
cache_glob_lookup_literal (const char *file_name,
const char *mime_types[],
int n_mime_types)
{
const char *ptr;
int i, min, max, mid, cmp;
for (i = 0; _caches[i]; i++)
{
XdgMimeCache *cache = _caches[i];
xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 12);
xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
xdg_uint32_t offset;
min = 0;
max = n_entries - 1;
while (max >= min)
{
mid = (min + max) / 2;
offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid);
ptr = cache->buffer + offset;
cmp = strcmp (ptr, file_name);
if (cmp < 0)
min = mid + 1;
else if (cmp > 0)
max = mid - 1;
else
{
offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid + 4);
mime_types[0] = (const char *)(cache->buffer + offset);
return 1;
}
}
}
return 0;
}
static int
cache_glob_lookup_fnmatch (const char *file_name,
const char *mime_types[],
int n_mime_types)
{
const char *mime_type;
const char *ptr;
int i, j, n;
n = 0;
for (i = 0; _caches[i]; i++)
{
XdgMimeCache *cache = _caches[i];
xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 20);
xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
for (j = 0; j < n_entries && n < n_mime_types; j++)
{
xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j);
xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j + 4);
ptr = cache->buffer + offset;
mime_type = cache->buffer + mimetype_offset;
/* FIXME: Not UTF-8 safe */
if (fnmatch (ptr, file_name, 0) == 0)
mime_types[n++] = mime_type;
}
if (n > 0)
return n;
}
return 0;
}
static int
cache_glob_node_lookup_suffix (XdgMimeCache *cache,
xdg_uint32_t n_entries,
xdg_uint32_t offset,
const char *suffix,
int ignore_case,
const char *mime_types[],
int n_mime_types)
{
xdg_unichar_t character;
xdg_unichar_t match_char;
xdg_uint32_t mimetype_offset;
xdg_uint32_t n_children;
xdg_uint32_t child_offset;
int min, max, mid, n, i;
character = _xdg_utf8_to_ucs4 (suffix);
if (ignore_case)
character = _xdg_ucs4_to_lower (character);
min = 0;
max = n_entries - 1;
while (max >= min)
{
mid = (min + max) / 2;
match_char = GET_UINT32 (cache->buffer, offset + 16 * mid);
if (match_char < character)
min = mid + 1;
else if (match_char > character)
max = mid - 1;
else
{
suffix = _xdg_utf8_next_char (suffix);
if (*suffix == '\0')
{
mimetype_offset = GET_UINT32 (cache->buffer, offset + 16 * mid + 4);
n = 0;
if (mimetype_offset)
mime_types[n++] = cache->buffer + mimetype_offset;
n_children = GET_UINT32 (cache->buffer, offset + 16 * mid + 8);
child_offset = GET_UINT32 (cache->buffer, offset + 16 * mid + 12);
i = 0;
while (n < n_mime_types && i < n_children)
{
match_char = GET_UINT32 (cache->buffer, child_offset + 16 * i);
mimetype_offset = GET_UINT32 (cache->buffer, offset + 16 * i + 4);
if (match_char != 0)
break;
mime_types[n++] = cache->buffer + mimetype_offset;
i++;
}
return n;
}
else
{
n_children = GET_UINT32 (cache->buffer, offset + 16 * mid + 8);
child_offset = GET_UINT32 (cache->buffer, offset + 16 * mid + 12);
return cache_glob_node_lookup_suffix (cache,
n_children, child_offset,
suffix, ignore_case,
mime_types,
n_mime_types);
}
}
}
return 0;
}
static int
cache_glob_lookup_suffix (const char *suffix,
int ignore_case,
const char *mime_types[],
int n_mime_types)
{
int i, n;
for (i = 0; _caches[i]; i++)
{
XdgMimeCache *cache = _caches[i];
xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 16);
xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4);
n = cache_glob_node_lookup_suffix (cache,
n_entries, offset,
suffix, ignore_case,
mime_types,
n_mime_types);
if (n > 0)
return n;
}
return 0;
}
static void
find_stopchars (char *stopchars)
{
int i, j, k, l;
k = 0;
for (i = 0; _caches[i]; i++)
{
XdgMimeCache *cache = _caches[i];
xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 16);
xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4);
for (j = 0; j < n_entries; j++)
{
xdg_uint32_t match_char = GET_UINT32 (cache->buffer, offset);
if (match_char < 128)
{
for (l = 0; l < k; l++)
if (stopchars[l] == match_char)
break;
if (l == k)
{
stopchars[k] = (char) match_char;
k++;
}
}
offset += 16;
}
}
stopchars[k] = '\0';
}
static int
cache_glob_lookup_file_name (const char *file_name,
const char *mime_types[],
int n_mime_types)
{
const char *ptr;
char stopchars[128];
int n;
assert (file_name != NULL);
/* First, check the literals */
n = cache_glob_lookup_literal (file_name, mime_types, n_mime_types);
if (n > 0)
return n;
find_stopchars (stopchars);
/* Next, check suffixes */
ptr = strpbrk (file_name, stopchars);
while (ptr)
{
n = cache_glob_lookup_suffix (ptr, FALSE, mime_types, n_mime_types);
if (n > 0)
return n;
n = cache_glob_lookup_suffix (ptr, TRUE, mime_types, n_mime_types);
if (n > 0)
return n;
ptr = strpbrk (ptr + 1, stopchars);
}
/* Last, try fnmatch */
return cache_glob_lookup_fnmatch (file_name, mime_types, n_mime_types);
}
int
_xdg_mime_cache_get_max_buffer_extents (void)
{
xdg_uint32_t offset;
xdg_uint32_t max_extent;
int i;
max_extent = 0;
for (i = 0; _caches[i]; i++)
{
XdgMimeCache *cache = _caches[i];
offset = GET_UINT32 (cache->buffer, 24);
max_extent = MAX (max_extent, GET_UINT32 (cache->buffer, offset + 4));
}
return max_extent;
}
static const char *
cache_get_mime_type_for_data (const void *data,
size_t len,
const char *mime_types[],
int n_mime_types)
{
const char *mime_type;
int i, n, priority;
priority = 0;
mime_type = NULL;
for (i = 0; _caches[i]; i++)
{
XdgMimeCache *cache = _caches[i];
int prio;
const char *match;
match = cache_magic_lookup_data (cache, data, len, &prio,
mime_types, n_mime_types);
if (prio > priority)
{
priority = prio;
mime_type = match;
}
}
if (priority > 0)
return mime_type;
for (n = 0; n < n_mime_types; n++)
{
if (mime_types[n])
return mime_types[n];
}
return XDG_MIME_TYPE_UNKNOWN;
}
const char *
_xdg_mime_cache_get_mime_type_for_data (const void *data,
size_t len)
{
return cache_get_mime_type_for_data (data, len, NULL, 0);
}
const char *
_xdg_mime_cache_get_mime_type_for_file (const char *file_name,
struct stat *statbuf)
{
const char *mime_type;
const char *mime_types[2];
FILE *file;
unsigned char *data;
int max_extent;
int bytes_read;
struct stat buf;
const char *base_name;
int n;
if (file_name == NULL)
return NULL;
if (! _xdg_utf8_validate (file_name))
return NULL;
base_name = _xdg_get_base_name (file_name);
n = cache_glob_lookup_file_name (base_name, mime_types, 2);
if (n == 1)
return mime_types[0];
if (!statbuf)
{
if (stat (file_name, &buf) != 0)
return XDG_MIME_TYPE_UNKNOWN;
statbuf = &buf;
}
if (!S_ISREG (statbuf->st_mode))
return XDG_MIME_TYPE_UNKNOWN;
/* FIXME: Need to make sure that max_extent isn't totally broken. This could
* be large and need getting from a stream instead of just reading it all
* in. */
max_extent = _xdg_mime_cache_get_max_buffer_extents ();
data = malloc (max_extent);
if (data == NULL)
return XDG_MIME_TYPE_UNKNOWN;
file = fopen (file_name, "r");
if (file == NULL)
{
free (data);
return XDG_MIME_TYPE_UNKNOWN;
}
bytes_read = fread (data, 1, max_extent, file);
if (ferror (file))
{
free (data);
fclose (file);
return XDG_MIME_TYPE_UNKNOWN;
}
mime_type = cache_get_mime_type_for_data (data, bytes_read,
mime_types, n);
free (data);
fclose (file);
return mime_type;
}
const char *
_xdg_mime_cache_get_mime_type_from_file_name (const char *file_name)
{
const char *mime_type;
if (cache_glob_lookup_file_name (file_name, &mime_type, 1))
return mime_type;
else
return XDG_MIME_TYPE_UNKNOWN;
}
#if 1
static int
is_super_type (const char *mime)
{
int length;
const char *type;
length = strlen (mime);
type = &(mime[length - 2]);
if (strcmp (type, "/*") == 0)
return 1;
return 0;
}
#endif
int
_xdg_mime_cache_mime_type_subclass (const char *mime,
const char *base)
{
const char *umime, *ubase;
int i, j, min, max, med, cmp;
umime = _xdg_mime_cache_unalias_mime_type (mime);
ubase = _xdg_mime_cache_unalias_mime_type (base);
if (strcmp (umime, ubase) == 0)
return 1;
/* We really want to handle text/ * in GtkFileFilter, so we just
* turn on the supertype matching
*/
#if 1
/* Handle supertypes */
if (is_super_type (ubase) &&
xdg_mime_media_type_equal (umime, ubase))
return 1;
#endif
/* Handle special cases text/plain and application/octet-stream */
if (strcmp (ubase, "text/plain") == 0 &&
strncmp (umime, "text/", 5) == 0)
return 1;
if (strcmp (ubase, "application/octet-stream") == 0)
return 1;
for (i = 0; _caches[i]; i++)
{
XdgMimeCache *cache = _caches[i];
xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 8);
xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
xdg_uint32_t offset, n_parents, parent_offset;
min = 0;
max = n_entries - 1;
while (max >= min)
{
med = (min + max)/2;
offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * med);
cmp = strcmp (cache->buffer + offset, umime);
if (cmp < 0)
min = med + 1;
else if (cmp > 0)
max = med - 1;
else
{
offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * med + 4);
n_parents = GET_UINT32 (cache->buffer, offset);
for (j = 0; j < n_parents; j++)
{
parent_offset = GET_UINT32 (cache->buffer, offset + 4 + 4 * j);
if (_xdg_mime_cache_mime_type_subclass (cache->buffer + parent_offset, ubase))
return 1;
}
break;
}
}
}
return 0;
}
const char *
_xdg_mime_cache_unalias_mime_type (const char *mime)
{
const char *lookup;
lookup = cache_alias_lookup (mime);
if (lookup)
return lookup;
return mime;
}
char **
_xdg_mime_cache_list_mime_parents (const char *mime)
{
int i, j, k, p;
char *all_parents[128]; /* we'll stop at 128 */
char **result;
mime = xdg_mime_unalias_mime_type (mime);
p = 0;
for (i = 0; _caches[i]; i++)
{
XdgMimeCache *cache = _caches[i];
xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 8);
xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
for (j = 0; j < n_entries; j++)
{
xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j);
xdg_uint32_t parents_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j + 4);
if (strcmp (cache->buffer + mimetype_offset, mime) == 0)
{
xdg_uint32_t parent_mime_offset;
xdg_uint32_t n_parents = GET_UINT32 (cache->buffer, parents_offset);
for (k = 0; k < n_parents && p < 127; k++)
{
parent_mime_offset = GET_UINT32 (cache->buffer, parents_offset + 4 + 4 * k);
all_parents[p++] = cache->buffer + parent_mime_offset;
}
break;
}
}
}
all_parents[p++] = 0;
result = (char **) malloc (p * sizeof (char *));
memcpy (result, all_parents, p * sizeof (char *));
return result;
}

View File

@ -0,0 +1,63 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmimecache.h: Private file. Datastructure for mmapped caches.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2005 Matthias Clasen <mclasen@redhat.com>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __XDG_MIME_CACHE_H__
#define __XDG_MIME_CACHE_H__
#include "xdgmime.h"
typedef struct _XdgMimeCache XdgMimeCache;
#ifdef XDG_PREFIX
#define _xdg_mime_cache_new_from_file XDG_ENTRY(cache_new_from_file)
#define _xdg_mime_cache_ref XDG_ENTRY(cache_ref)
#define _xdg_mime_cache_unref XDG_ENTRY(cache_unref)
#endif
extern XdgMimeCache **_caches;
XdgMimeCache *_xdg_mime_cache_new_from_file (const char *file_name);
XdgMimeCache *_xdg_mime_cache_ref (XdgMimeCache *cache);
void _xdg_mime_cache_unref (XdgMimeCache *cache);
const char *_xdg_mime_cache_get_mime_type_for_data (const void *data,
size_t len);
const char *_xdg_mime_cache_get_mime_type_for_file (const char *file_name,
struct stat *statbuf);
const char *_xdg_mime_cache_get_mime_type_from_file_name (const char *file_name);
int _xdg_mime_cache_is_valid_mime_type (const char *mime_type);
int _xdg_mime_cache_mime_type_equal (const char *mime_a,
const char *mime_b);
int _xdg_mime_cache_media_type_equal (const char *mime_a,
const char *mime_b);
int _xdg_mime_cache_mime_type_subclass (const char *mime_a,
const char *mime_b);
char **_xdg_mime_cache_list_mime_parents (const char *mime);
const char *_xdg_mime_cache_unalias_mime_type (const char *mime);
int _xdg_mime_cache_get_max_buffer_extents (void);
#endif /* __XDG_MIME_CACHE_H__ */

547
lib/xdgmime/xdgmimeglob.c Normal file
View File

@ -0,0 +1,547 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmimeglob.c: Private file. Datastructure for storing the globs.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2003 Red Hat, Inc.
* Copyright (C) 2003 Jonathan Blandford <jrb@alum.mit.edu>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "xdgmimeglob.h"
#include "xdgmimeint.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <fnmatch.h>
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
typedef struct XdgGlobHashNode XdgGlobHashNode;
typedef struct XdgGlobList XdgGlobList;
struct XdgGlobHashNode
{
xdg_unichar_t character;
const char *mime_type;
XdgGlobHashNode *next;
XdgGlobHashNode *child;
};
struct XdgGlobList
{
const char *data;
const char *mime_type;
XdgGlobList *next;
};
struct XdgGlobHash
{
XdgGlobList *literal_list;
XdgGlobHashNode *simple_node;
XdgGlobList *full_list;
};
/* XdgGlobList
*/
static XdgGlobList *
_xdg_glob_list_new (void)
{
XdgGlobList *new_element;
new_element = calloc (1, sizeof (XdgGlobList));
return new_element;
}
/* Frees glob_list and all of it's children */
static void
_xdg_glob_list_free (XdgGlobList *glob_list)
{
XdgGlobList *ptr, *next;
ptr = glob_list;
while (ptr != NULL)
{
next = ptr->next;
if (ptr->data)
free ((void *) ptr->data);
if (ptr->mime_type)
free ((void *) ptr->mime_type);
free (ptr);
ptr = next;
}
}
static XdgGlobList *
_xdg_glob_list_append (XdgGlobList *glob_list,
void *data,
const char *mime_type)
{
XdgGlobList *new_element;
XdgGlobList *tmp_element;
new_element = _xdg_glob_list_new ();
new_element->data = data;
new_element->mime_type = mime_type;
if (glob_list == NULL)
return new_element;
tmp_element = glob_list;
while (tmp_element->next != NULL)
tmp_element = tmp_element->next;
tmp_element->next = new_element;
return glob_list;
}
#if 0
static XdgGlobList *
_xdg_glob_list_prepend (XdgGlobList *glob_list,
void *data,
const char *mime_type)
{
XdgGlobList *new_element;
new_element = _xdg_glob_list_new ();
new_element->data = data;
new_element->next = glob_list;
new_element->mime_type = mime_type;
return new_element;
}
#endif
/* XdgGlobHashNode
*/
static XdgGlobHashNode *
_xdg_glob_hash_node_new (void)
{
XdgGlobHashNode *glob_hash_node;
glob_hash_node = calloc (1, sizeof (XdgGlobHashNode));
return glob_hash_node;
}
static void
_xdg_glob_hash_node_dump (XdgGlobHashNode *glob_hash_node,
int depth)
{
int i;
for (i = 0; i < depth; i++)
printf (" ");
printf ("%c", (char)glob_hash_node->character);
if (glob_hash_node->mime_type)
printf (" - %s\n", glob_hash_node->mime_type);
else
printf ("\n");
if (glob_hash_node->child)
_xdg_glob_hash_node_dump (glob_hash_node->child, depth + 1);
if (glob_hash_node->next)
_xdg_glob_hash_node_dump (glob_hash_node->next, depth);
}
static XdgGlobHashNode *
_xdg_glob_hash_insert_text (XdgGlobHashNode *glob_hash_node,
const char *text,
const char *mime_type)
{
XdgGlobHashNode *node;
xdg_unichar_t character;
character = _xdg_utf8_to_ucs4 (text);
if ((glob_hash_node == NULL) ||
(character < glob_hash_node->character))
{
node = _xdg_glob_hash_node_new ();
node->character = character;
node->next = glob_hash_node;
glob_hash_node = node;
}
else if (character == glob_hash_node->character)
{
node = glob_hash_node;
}
else
{
XdgGlobHashNode *prev_node;
int found_node = FALSE;
/* Look for the first character of text in glob_hash_node, and insert it if we
* have to.*/
prev_node = glob_hash_node;
node = prev_node->next;
while (node != NULL)
{
if (character < node->character)
{
node = _xdg_glob_hash_node_new ();
node->character = character;
node->next = prev_node->next;
prev_node->next = node;
found_node = TRUE;
break;
}
else if (character == node->character)
{
found_node = TRUE;
break;
}
prev_node = node;
node = node->next;
}
if (! found_node)
{
node = _xdg_glob_hash_node_new ();
node->character = character;
node->next = prev_node->next;
prev_node->next = node;
}
}
text = _xdg_utf8_next_char (text);
if (*text == '\000')
{
if (node->mime_type)
{
if (strcmp (node->mime_type, mime_type))
{
XdgGlobHashNode *child;
int found_node = FALSE;
child = node->child;
while (child && child->character == '\0')
{
if (strcmp (child->mime_type, mime_type) == 0)
{
found_node = TRUE;
break;
}
child = child->next;
}
if (!found_node)
{
child = _xdg_glob_hash_node_new ();
child->character = '\000';
child->mime_type = mime_type;
child->child = NULL;
child->next = node->child;
node->child = child;
}
}
}
else
{
node->mime_type = mime_type;
}
}
else
{
node->child = _xdg_glob_hash_insert_text (node->child, text, mime_type);
}
return glob_hash_node;
}
static int
_xdg_glob_hash_node_lookup_file_name (XdgGlobHashNode *glob_hash_node,
const char *file_name,
int ignore_case,
const char *mime_types[],
int n_mime_types)
{
int n;
XdgGlobHashNode *node;
xdg_unichar_t character;
if (glob_hash_node == NULL)
return 0;
character = _xdg_utf8_to_ucs4 (file_name);
if (ignore_case)
character = _xdg_ucs4_to_lower(character);
for (node = glob_hash_node; node && character >= node->character; node = node->next)
{
if (character == node->character)
{
file_name = _xdg_utf8_next_char (file_name);
if (*file_name == '\000')
{
n = 0;
if (node->mime_type)
mime_types[n++] = node->mime_type;
node = node->child;
while (n < n_mime_types && node && node->character == 0)
{
if (node->mime_type)
mime_types[n++] = node->mime_type;
node = node->next;
}
}
else
{
n = _xdg_glob_hash_node_lookup_file_name (node->child,
file_name,
ignore_case,
mime_types,
n_mime_types);
}
return n;
}
}
return 0;
}
int
_xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
const char *file_name,
const char *mime_types[],
int n_mime_types)
{
XdgGlobList *list;
const char *ptr;
char stopchars[128];
int i, n;
XdgGlobHashNode *node;
/* First, check the literals */
assert (file_name != NULL && n_mime_types > 0);
for (list = glob_hash->literal_list; list; list = list->next)
{
if (strcmp ((const char *)list->data, file_name) == 0)
{
mime_types[0] = list->mime_type;
return 1;
}
}
i = 0;
for (node = glob_hash->simple_node; node; node = node->next)
{
if (node->character < 128)
stopchars[i++] = (char)node->character;
}
stopchars[i] = '\0';
ptr = strpbrk (file_name, stopchars);
while (ptr)
{
n = _xdg_glob_hash_node_lookup_file_name (glob_hash->simple_node, ptr, FALSE,
mime_types, n_mime_types);
if (n > 0)
return n;
n = _xdg_glob_hash_node_lookup_file_name (glob_hash->simple_node, ptr, TRUE,
mime_types, n_mime_types);
if (n > 0)
return n;
ptr = strpbrk (ptr + 1, stopchars);
}
/* FIXME: Not UTF-8 safe */
n = 0;
for (list = glob_hash->full_list; list && n < n_mime_types; list = list->next)
{
if (fnmatch ((const char *)list->data, file_name, 0) == 0)
mime_types[n++] = list->mime_type;
}
return n;
}
/* XdgGlobHash
*/
XdgGlobHash *
_xdg_glob_hash_new (void)
{
XdgGlobHash *glob_hash;
glob_hash = calloc (1, sizeof (XdgGlobHash));
return glob_hash;
}
static void
_xdg_glob_hash_free_nodes (XdgGlobHashNode *node)
{
if (node)
{
if (node->child)
_xdg_glob_hash_free_nodes (node->child);
if (node->next)
_xdg_glob_hash_free_nodes (node->next);
if (node->mime_type)
free ((void *) node->mime_type);
free (node);
}
}
void
_xdg_glob_hash_free (XdgGlobHash *glob_hash)
{
_xdg_glob_list_free (glob_hash->literal_list);
_xdg_glob_list_free (glob_hash->full_list);
_xdg_glob_hash_free_nodes (glob_hash->simple_node);
free (glob_hash);
}
XdgGlobType
_xdg_glob_determine_type (const char *glob)
{
const char *ptr;
int maybe_in_simple_glob = FALSE;
int first_char = TRUE;
ptr = glob;
while (*ptr != '\000')
{
if (*ptr == '*' && first_char)
maybe_in_simple_glob = TRUE;
else if (*ptr == '\\' || *ptr == '[' || *ptr == '?' || *ptr == '*')
return XDG_GLOB_FULL;
first_char = FALSE;
ptr = _xdg_utf8_next_char (ptr);
}
if (maybe_in_simple_glob)
return XDG_GLOB_SIMPLE;
else
return XDG_GLOB_LITERAL;
}
/* glob must be valid UTF-8 */
void
_xdg_glob_hash_append_glob (XdgGlobHash *glob_hash,
const char *glob,
const char *mime_type)
{
XdgGlobType type;
assert (glob_hash != NULL);
assert (glob != NULL);
type = _xdg_glob_determine_type (glob);
switch (type)
{
case XDG_GLOB_LITERAL:
glob_hash->literal_list = _xdg_glob_list_append (glob_hash->literal_list, strdup (glob), strdup (mime_type));
break;
case XDG_GLOB_SIMPLE:
glob_hash->simple_node = _xdg_glob_hash_insert_text (glob_hash->simple_node, glob + 1, strdup (mime_type));
break;
case XDG_GLOB_FULL:
glob_hash->full_list = _xdg_glob_list_append (glob_hash->full_list, strdup (glob), strdup (mime_type));
break;
}
}
void
_xdg_glob_hash_dump (XdgGlobHash *glob_hash)
{
XdgGlobList *list;
printf ("LITERAL STRINGS\n");
if (glob_hash->literal_list == NULL)
{
printf (" None\n");
}
else
{
for (list = glob_hash->literal_list; list; list = list->next)
printf (" %s - %s\n", (char *)list->data, list->mime_type);
}
printf ("\nSIMPLE GLOBS\n");
_xdg_glob_hash_node_dump (glob_hash->simple_node, 4);
printf ("\nFULL GLOBS\n");
if (glob_hash->full_list == NULL)
{
printf (" None\n");
}
else
{
for (list = glob_hash->full_list; list; list = list->next)
printf (" %s - %s\n", (char *)list->data, list->mime_type);
}
}
void
_xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
const char *file_name)
{
FILE *glob_file;
char line[255];
glob_file = fopen (file_name, "r");
if (glob_file == NULL)
return;
/* FIXME: Not UTF-8 safe. Doesn't work if lines are greater than 255 chars.
* Blah */
while (fgets (line, 255, glob_file) != NULL)
{
char *colon;
if (line[0] == '#')
continue;
colon = strchr (line, ':');
if (colon == NULL)
continue;
*(colon++) = '\000';
colon[strlen (colon) -1] = '\000';
_xdg_glob_hash_append_glob (glob_hash, colon, line);
}
fclose (glob_file);
}

67
lib/xdgmime/xdgmimeglob.h Normal file
View File

@ -0,0 +1,67 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmimeglob.h: Private file. Datastructure for storing the globs.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2003 Red Hat, Inc.
* Copyright (C) 2003 Jonathan Blandford <jrb@alum.mit.edu>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __XDG_MIME_GLOB_H__
#define __XDG_MIME_GLOB_H__
#include "xdgmime.h"
typedef struct XdgGlobHash XdgGlobHash;
typedef enum
{
XDG_GLOB_LITERAL, /* Makefile */
XDG_GLOB_SIMPLE, /* *.gif */
XDG_GLOB_FULL /* x*.[ch] */
} XdgGlobType;
#ifdef XDG_PREFIX
#define _xdg_mime_glob_read_from_file XDG_ENTRY(glob_read_from_file)
#define _xdg_glob_hash_new XDG_ENTRY(hash_new)
#define _xdg_glob_hash_free XDG_ENTRY(hash_free)
#define _xdg_glob_hash_lookup_file_name XDG_ENTRY(hash_lookup_file_name)
#define _xdg_glob_hash_append_glob XDG_ENTRY(hash_append_glob)
#define _xdg_glob_determine_type XDG_ENTRY(determine_type)
#define _xdg_glob_hash_dump XDG_ENTRY(hash_dump)
#endif
void _xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
const char *file_name);
XdgGlobHash *_xdg_glob_hash_new (void);
void _xdg_glob_hash_free (XdgGlobHash *glob_hash);
int _xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
const char *text,
const char *mime_types[],
int n_mime_types);
void _xdg_glob_hash_append_glob (XdgGlobHash *glob_hash,
const char *glob,
const char *mime_type);
XdgGlobType _xdg_glob_determine_type (const char *glob);
void _xdg_glob_hash_dump (XdgGlobHash *glob_hash);
#endif /* __XDG_MIME_GLOB_H__ */

154
lib/xdgmime/xdgmimeint.c Normal file
View File

@ -0,0 +1,154 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmimeint.c: Internal defines and functions.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2003 Red Hat, Inc.
* Copyright (C) 2003 Jonathan Blandford <jrb@alum.mit.edu>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "xdgmimeint.h"
#include <ctype.h>
#include <string.h>
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
static const char _xdg_utf8_skip_data[256] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
};
const char * const _xdg_utf8_skip = _xdg_utf8_skip_data;
/* Returns the number of unprocessed characters. */
xdg_unichar_t
_xdg_utf8_to_ucs4(const char *source)
{
xdg_unichar_t ucs32;
if( ! ( *source & 0x80 ) )
{
ucs32 = *source;
}
else
{
int bytelength = 0;
xdg_unichar_t result;
if ( ! (*source & 0x40) )
{
ucs32 = *source;
}
else
{
if ( ! (*source & 0x20) )
{
result = *source++ & 0x1F;
bytelength = 2;
}
else if ( ! (*source & 0x10) )
{
result = *source++ & 0x0F;
bytelength = 3;
}
else if ( ! (*source & 0x08) )
{
result = *source++ & 0x07;
bytelength = 4;
}
else if ( ! (*source & 0x04) )
{
result = *source++ & 0x03;
bytelength = 5;
}
else if ( ! (*source & 0x02) )
{
result = *source++ & 0x01;
bytelength = 6;
}
else
{
result = *source++;
bytelength = 1;
}
for ( bytelength --; bytelength > 0; bytelength -- )
{
result <<= 6;
result |= *source++ & 0x3F;
}
ucs32 = result;
}
}
return ucs32;
}
/* hullo. this is great code. don't rewrite it */
xdg_unichar_t
_xdg_ucs4_to_lower (xdg_unichar_t source)
{
/* FIXME: Do a real to_upper sometime */
/* CaseFolding-3.2.0.txt has a table of rules. */
if ((source & 0xFF) == source)
return (xdg_unichar_t) tolower ((unsigned char) source);
return source;
}
int
_xdg_utf8_validate (const char *source)
{
/* FIXME: actually write */
return TRUE;
}
const char *
_xdg_get_base_name (const char *file_name)
{
const char *base_name;
if (file_name == NULL)
return NULL;
base_name = strrchr (file_name, '/');
if (base_name == NULL)
return file_name;
else
return base_name + 1;
}

73
lib/xdgmime/xdgmimeint.h Normal file
View File

@ -0,0 +1,73 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmimeint.h: Internal defines and functions.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2003 Red Hat, Inc.
* Copyright (C) 2003 Jonathan Blandford <jrb@alum.mit.edu>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __XDG_MIME_INT_H__
#define __XDG_MIME_INT_H__
#include "xdgmime.h"
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
/* FIXME: Needs to be configure check */
typedef unsigned int xdg_unichar_t;
typedef unsigned char xdg_uchar8_t;
typedef unsigned short xdg_uint16_t;
typedef unsigned int xdg_uint32_t;
#ifdef XDG_PREFIX
#define _xdg_utf8_skip XDG_ENTRY(utf8_skip)
#define _xdg_utf8_to_ucs4 XDG_ENTRY(utf8_to_ucs4)
#define _xdg_ucs4_to_lower XDG_ENTRY(ucs4_to_lower)
#define _xdg_utf8_validate XDG_ENTRY(utf8_validate)
#define _xdg_get_base_name XDG_ENTRY(get_ase_name)
#endif
#define SWAP_BE16_TO_LE16(val) (xdg_uint16_t)(((xdg_uint16_t)(val) << 8)|((xdg_uint16_t)(val) >> 8))
#define SWAP_BE32_TO_LE32(val) (xdg_uint32_t)((((xdg_uint32_t)(val) & 0xFF000000U) >> 24) | \
(((xdg_uint32_t)(val) & 0x00FF0000U) >> 8) | \
(((xdg_uint32_t)(val) & 0x0000FF00U) << 8) | \
(((xdg_uint32_t)(val) & 0x000000FFU) << 24))
/* UTF-8 utils
*/
extern const char *const _xdg_utf8_skip;
#define _xdg_utf8_next_char(p) (char *)((p) + _xdg_utf8_skip[*(unsigned char *)(p)])
#define _xdg_utf8_char_size(p) (int) (_xdg_utf8_skip[*(unsigned char *)(p)])
xdg_unichar_t _xdg_utf8_to_ucs4 (const char *source);
xdg_unichar_t _xdg_ucs4_to_lower (xdg_unichar_t source);
int _xdg_utf8_validate (const char *source);
const char *_xdg_get_base_name (const char *file_name);
#endif /* __XDG_MIME_INT_H__ */

807
lib/xdgmime/xdgmimemagic.c Normal file
View File

@ -0,0 +1,807 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmimemagic.: Private file. Datastructure for storing magic files.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2003 Red Hat, Inc.
* Copyright (C) 2003 Jonathan Blandford <jrb@alum.mit.edu>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <assert.h>
#include "xdgmimemagic.h"
#include "xdgmimeint.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
#if !defined getc_unlocked && !defined HAVE_GETC_UNLOCKED
# define getc_unlocked(fp) getc (fp)
#endif
typedef struct XdgMimeMagicMatch XdgMimeMagicMatch;
typedef struct XdgMimeMagicMatchlet XdgMimeMagicMatchlet;
typedef enum
{
XDG_MIME_MAGIC_SECTION,
XDG_MIME_MAGIC_MAGIC,
XDG_MIME_MAGIC_ERROR,
XDG_MIME_MAGIC_EOF
} XdgMimeMagicState;
struct XdgMimeMagicMatch
{
const char *mime_type;
int priority;
XdgMimeMagicMatchlet *matchlet;
XdgMimeMagicMatch *next;
};
struct XdgMimeMagicMatchlet
{
int indent;
int offset;
unsigned int value_length;
unsigned char *value;
unsigned char *mask;
unsigned int range_length;
unsigned int word_size;
XdgMimeMagicMatchlet *next;
};
struct XdgMimeMagic
{
XdgMimeMagicMatch *match_list;
int max_extent;
};
static XdgMimeMagicMatch *
_xdg_mime_magic_match_new (void)
{
return calloc (1, sizeof (XdgMimeMagicMatch));
}
static XdgMimeMagicMatchlet *
_xdg_mime_magic_matchlet_new (void)
{
XdgMimeMagicMatchlet *matchlet;
matchlet = malloc (sizeof (XdgMimeMagicMatchlet));
matchlet->indent = 0;
matchlet->offset = 0;
matchlet->value_length = 0;
matchlet->value = NULL;
matchlet->mask = NULL;
matchlet->range_length = 1;
matchlet->word_size = 1;
matchlet->next = NULL;
return matchlet;
}
static void
_xdg_mime_magic_matchlet_free (XdgMimeMagicMatchlet *mime_magic_matchlet)
{
if (mime_magic_matchlet)
{
if (mime_magic_matchlet->next)
_xdg_mime_magic_matchlet_free (mime_magic_matchlet->next);
if (mime_magic_matchlet->value)
free (mime_magic_matchlet->value);
if (mime_magic_matchlet->mask)
free (mime_magic_matchlet->mask);
free (mime_magic_matchlet);
}
}
/* Frees mime_magic_match and the remainder of its list
*/
static void
_xdg_mime_magic_match_free (XdgMimeMagicMatch *mime_magic_match)
{
XdgMimeMagicMatch *ptr, *next;
ptr = mime_magic_match;
while (ptr)
{
next = ptr->next;
if (ptr->mime_type)
free ((void *) ptr->mime_type);
if (ptr->matchlet)
_xdg_mime_magic_matchlet_free (ptr->matchlet);
free (ptr);
ptr = next;
}
}
/* Reads in a hunk of data until a newline character or a '\000' is hit. The
* returned string is null terminated, and doesn't include the newline.
*/
static unsigned char *
_xdg_mime_magic_read_to_newline (FILE *magic_file,
int *end_of_file)
{
unsigned char *retval;
int c;
int len, pos;
len = 128;
pos = 0;
retval = malloc (len);
*end_of_file = FALSE;
while (TRUE)
{
c = getc_unlocked (magic_file);
if (c == EOF)
{
*end_of_file = TRUE;
break;
}
if (c == '\n' || c == '\000')
break;
retval[pos++] = (unsigned char) c;
if (pos % 128 == 127)
{
len = len + 128;
retval = realloc (retval, len);
}
}
retval[pos] = '\000';
return retval;
}
/* Returns the number read from the file, or -1 if no number could be read.
*/
static int
_xdg_mime_magic_read_a_number (FILE *magic_file,
int *end_of_file)
{
/* LONG_MAX is about 20 characters on my system */
#define MAX_NUMBER_SIZE 30
char number_string[MAX_NUMBER_SIZE + 1];
int pos = 0;
int c;
long retval = -1;
while (TRUE)
{
c = getc_unlocked (magic_file);
if (c == EOF)
{
*end_of_file = TRUE;
break;
}
if (! isdigit (c))
{
ungetc (c, magic_file);
break;
}
number_string[pos] = (char) c;
pos++;
if (pos == MAX_NUMBER_SIZE)
break;
}
if (pos > 0)
{
number_string[pos] = '\000';
errno = 0;
retval = strtol (number_string, NULL, 10);
if ((retval < INT_MIN) || (retval > INT_MAX) || (errno != 0))
return -1;
}
return retval;
}
/* Headers are of the format:
* [<priority>:<mime-type>]
*/
static XdgMimeMagicState
_xdg_mime_magic_parse_header (FILE *magic_file, XdgMimeMagicMatch *match)
{
int c;
char *buffer;
char *end_ptr;
int end_of_file = 0;
assert (magic_file != NULL);
assert (match != NULL);
c = getc_unlocked (magic_file);
if (c == EOF)
return XDG_MIME_MAGIC_EOF;
if (c != '[')
return XDG_MIME_MAGIC_ERROR;
match->priority = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
if (end_of_file)
return XDG_MIME_MAGIC_EOF;
if (match->priority == -1)
return XDG_MIME_MAGIC_ERROR;
c = getc_unlocked (magic_file);
if (c == EOF)
return XDG_MIME_MAGIC_EOF;
if (c != ':')
return XDG_MIME_MAGIC_ERROR;
buffer = (char *)_xdg_mime_magic_read_to_newline (magic_file, &end_of_file);
if (end_of_file)
return XDG_MIME_MAGIC_EOF;
end_ptr = buffer;
while (*end_ptr != ']' && *end_ptr != '\000' && *end_ptr != '\n')
end_ptr++;
if (*end_ptr != ']')
{
free (buffer);
return XDG_MIME_MAGIC_ERROR;
}
*end_ptr = '\000';
match->mime_type = strdup (buffer);
free (buffer);
return XDG_MIME_MAGIC_MAGIC;
}
static XdgMimeMagicState
_xdg_mime_magic_parse_error (FILE *magic_file)
{
int c;
while (1)
{
c = getc_unlocked (magic_file);
if (c == EOF)
return XDG_MIME_MAGIC_EOF;
if (c == '\n')
return XDG_MIME_MAGIC_SECTION;
}
}
/* Headers are of the format:
* [ indent ] ">" start-offset "=" value
* [ "&" mask ] [ "~" word-size ] [ "+" range-length ] "\n"
*/
static XdgMimeMagicState
_xdg_mime_magic_parse_magic_line (FILE *magic_file,
XdgMimeMagicMatch *match)
{
XdgMimeMagicMatchlet *matchlet;
int c;
int end_of_file;
int indent = 0;
int bytes_read;
assert (magic_file != NULL);
/* Sniff the buffer to make sure it's a valid line */
c = getc_unlocked (magic_file);
if (c == EOF)
return XDG_MIME_MAGIC_EOF;
else if (c == '[')
{
ungetc (c, magic_file);
return XDG_MIME_MAGIC_SECTION;
}
else if (c == '\n')
return XDG_MIME_MAGIC_MAGIC;
/* At this point, it must be a digit or a '>' */
end_of_file = FALSE;
if (isdigit (c))
{
ungetc (c, magic_file);
indent = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
if (end_of_file)
return XDG_MIME_MAGIC_EOF;
if (indent == -1)
return XDG_MIME_MAGIC_ERROR;
c = getc_unlocked (magic_file);
if (c == EOF)
return XDG_MIME_MAGIC_EOF;
}
if (c != '>')
return XDG_MIME_MAGIC_ERROR;
matchlet = _xdg_mime_magic_matchlet_new ();
matchlet->indent = indent;
matchlet->offset = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
if (end_of_file)
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_EOF;
}
if (matchlet->offset == -1)
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_ERROR;
}
c = getc_unlocked (magic_file);
if (c == EOF)
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_EOF;
}
else if (c != '=')
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_ERROR;
}
/* Next two bytes determine how long the value is */
matchlet->value_length = 0;
c = getc_unlocked (magic_file);
if (c == EOF)
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_EOF;
}
matchlet->value_length = c & 0xFF;
matchlet->value_length = matchlet->value_length << 8;
c = getc_unlocked (magic_file);
if (c == EOF)
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_EOF;
}
matchlet->value_length = matchlet->value_length + (c & 0xFF);
matchlet->value = malloc (matchlet->value_length);
/* OOM */
if (matchlet->value == NULL)
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_ERROR;
}
bytes_read = fread (matchlet->value, 1, matchlet->value_length, magic_file);
if (bytes_read != matchlet->value_length)
{
_xdg_mime_magic_matchlet_free (matchlet);
if (feof (magic_file))
return XDG_MIME_MAGIC_EOF;
else
return XDG_MIME_MAGIC_ERROR;
}
c = getc_unlocked (magic_file);
if (c == '&')
{
matchlet->mask = malloc (matchlet->value_length);
/* OOM */
if (matchlet->mask == NULL)
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_ERROR;
}
bytes_read = fread (matchlet->mask, 1, matchlet->value_length, magic_file);
if (bytes_read != matchlet->value_length)
{
_xdg_mime_magic_matchlet_free (matchlet);
if (feof (magic_file))
return XDG_MIME_MAGIC_EOF;
else
return XDG_MIME_MAGIC_ERROR;
}
c = getc_unlocked (magic_file);
}
if (c == '~')
{
matchlet->word_size = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
if (end_of_file)
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_EOF;
}
if (matchlet->word_size != 0 &&
matchlet->word_size != 1 &&
matchlet->word_size != 2 &&
matchlet->word_size != 4)
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_ERROR;
}
c = getc_unlocked (magic_file);
}
if (c == '+')
{
matchlet->range_length = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
if (end_of_file)
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_EOF;
}
if (matchlet->range_length == -1)
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_ERROR;
}
c = getc_unlocked (magic_file);
}
if (c == '\n')
{
/* We clean up the matchlet, byte swapping if needed */
if (matchlet->word_size > 1)
{
int i;
if (matchlet->value_length % matchlet->word_size != 0)
{
_xdg_mime_magic_matchlet_free (matchlet);
return XDG_MIME_MAGIC_ERROR;
}
/* FIXME: need to get this defined in a <config.h> style file */
#if LITTLE_ENDIAN
for (i = 0; i < matchlet->value_length; i = i + matchlet->word_size)
{
if (matchlet->word_size == 2)
*((xdg_uint16_t *) matchlet->value + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->value + i)));
else if (matchlet->word_size == 4)
*((xdg_uint32_t *) matchlet->value + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->value + i)));
if (matchlet->mask)
{
if (matchlet->word_size == 2)
*((xdg_uint16_t *) matchlet->mask + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->mask + i)));
else if (matchlet->word_size == 4)
*((xdg_uint32_t *) matchlet->mask + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->mask + i)));
}
}
#endif
}
matchlet->next = match->matchlet;
match->matchlet = matchlet;
return XDG_MIME_MAGIC_MAGIC;
}
_xdg_mime_magic_matchlet_free (matchlet);
if (c == EOF)
return XDG_MIME_MAGIC_EOF;
return XDG_MIME_MAGIC_ERROR;
}
static int
_xdg_mime_magic_matchlet_compare_to_data (XdgMimeMagicMatchlet *matchlet,
const void *data,
size_t len)
{
int i, j;
for (i = matchlet->offset; i < matchlet->offset + matchlet->range_length; i++)
{
int valid_matchlet = TRUE;
if (i + matchlet->value_length > len)
return FALSE;
if (matchlet->mask)
{
for (j = 0; j < matchlet->value_length; j++)
{
if ((matchlet->value[j] & matchlet->mask[j]) !=
((((unsigned char *) data)[j + i]) & matchlet->mask[j]))
{
valid_matchlet = FALSE;
break;
}
}
}
else
{
for (j = 0; j < matchlet->value_length; j++)
{
if (matchlet->value[j] != ((unsigned char *) data)[j + i])
{
valid_matchlet = FALSE;
break;
}
}
}
if (valid_matchlet)
return TRUE;
}
return FALSE;
}
static int
_xdg_mime_magic_matchlet_compare_level (XdgMimeMagicMatchlet *matchlet,
const void *data,
size_t len,
int indent)
{
while ((matchlet != NULL) && (matchlet->indent == indent))
{
if (_xdg_mime_magic_matchlet_compare_to_data (matchlet, data, len))
{
if ((matchlet->next == NULL) ||
(matchlet->next->indent <= indent))
return TRUE;
if (_xdg_mime_magic_matchlet_compare_level (matchlet->next,
data,
len,
indent + 1))
return TRUE;
}
do
{
matchlet = matchlet->next;
}
while (matchlet && matchlet->indent > indent);
}
return FALSE;
}
static int
_xdg_mime_magic_match_compare_to_data (XdgMimeMagicMatch *match,
const void *data,
size_t len)
{
return _xdg_mime_magic_matchlet_compare_level (match->matchlet, data, len, 0);
}
static void
_xdg_mime_magic_insert_match (XdgMimeMagic *mime_magic,
XdgMimeMagicMatch *match)
{
XdgMimeMagicMatch *list;
if (mime_magic->match_list == NULL)
{
mime_magic->match_list = match;
return;
}
if (match->priority > mime_magic->match_list->priority)
{
match->next = mime_magic->match_list;
mime_magic->match_list = match;
return;
}
list = mime_magic->match_list;
while (list->next != NULL)
{
if (list->next->priority < match->priority)
{
match->next = list->next;
list->next = match;
return;
}
list = list->next;
}
list->next = match;
match->next = NULL;
}
XdgMimeMagic *
_xdg_mime_magic_new (void)
{
return calloc (1, sizeof (XdgMimeMagic));
}
void
_xdg_mime_magic_free (XdgMimeMagic *mime_magic)
{
if (mime_magic) {
_xdg_mime_magic_match_free (mime_magic->match_list);
free (mime_magic);
}
}
int
_xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic)
{
return mime_magic->max_extent;
}
const char *
_xdg_mime_magic_lookup_data (XdgMimeMagic *mime_magic,
const void *data,
size_t len,
const char *mime_types[],
int n_mime_types)
{
XdgMimeMagicMatch *match;
const char *mime_type;
int n;
mime_type = NULL;
for (match = mime_magic->match_list; match; match = match->next)
{
if (_xdg_mime_magic_match_compare_to_data (match, data, len))
{
if ((mime_type == NULL) || (_xdg_mime_mime_type_subclass (match->mime_type, mime_type))) {
mime_type = match->mime_type;
}
}
else
{
for (n = 0; n < n_mime_types; n++)
{
if (mime_types[n] &&
_xdg_mime_mime_type_equal (mime_types[n], match->mime_type))
mime_types[n] = NULL;
}
}
}
if (mime_type == NULL)
{
for (n = 0; n < n_mime_types; n++)
{
if (mime_types[n])
mime_type = mime_types[n];
}
}
return mime_type;
}
static void
_xdg_mime_update_mime_magic_extents (XdgMimeMagic *mime_magic)
{
XdgMimeMagicMatch *match;
int max_extent = 0;
for (match = mime_magic->match_list; match; match = match->next)
{
XdgMimeMagicMatchlet *matchlet;
for (matchlet = match->matchlet; matchlet; matchlet = matchlet->next)
{
int extent;
extent = matchlet->value_length + matchlet->offset + matchlet->range_length;
if (max_extent < extent)
max_extent = extent;
}
}
mime_magic->max_extent = max_extent;
}
static XdgMimeMagicMatchlet *
_xdg_mime_magic_matchlet_mirror (XdgMimeMagicMatchlet *matchlets)
{
XdgMimeMagicMatchlet *new_list;
XdgMimeMagicMatchlet *tmp;
if ((matchlets == NULL) || (matchlets->next == NULL))
return matchlets;
new_list = NULL;
tmp = matchlets;
while (tmp != NULL)
{
XdgMimeMagicMatchlet *matchlet;
matchlet = tmp;
tmp = tmp->next;
matchlet->next = new_list;
new_list = matchlet;
}
return new_list;
}
static void
_xdg_mime_magic_read_magic_file (XdgMimeMagic *mime_magic,
FILE *magic_file)
{
XdgMimeMagicState state;
XdgMimeMagicMatch *match = NULL; /* Quiet compiler */
state = XDG_MIME_MAGIC_SECTION;
while (state != XDG_MIME_MAGIC_EOF)
{
switch (state)
{
case XDG_MIME_MAGIC_SECTION:
match = _xdg_mime_magic_match_new ();
state = _xdg_mime_magic_parse_header (magic_file, match);
if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
_xdg_mime_magic_match_free (match);
break;
case XDG_MIME_MAGIC_MAGIC:
state = _xdg_mime_magic_parse_magic_line (magic_file, match);
if (state == XDG_MIME_MAGIC_SECTION ||
(state == XDG_MIME_MAGIC_EOF && match->mime_type))
{
match->matchlet = _xdg_mime_magic_matchlet_mirror (match->matchlet);
_xdg_mime_magic_insert_match (mime_magic, match);
}
else if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
_xdg_mime_magic_match_free (match);
break;
case XDG_MIME_MAGIC_ERROR:
state = _xdg_mime_magic_parse_error (magic_file);
break;
case XDG_MIME_MAGIC_EOF:
default:
/* Make the compiler happy */
assert (0);
}
}
_xdg_mime_update_mime_magic_extents (mime_magic);
}
void
_xdg_mime_magic_read_from_file (XdgMimeMagic *mime_magic,
const char *file_name)
{
FILE *magic_file;
char header[12];
magic_file = fopen (file_name, "r");
if (magic_file == NULL)
return;
if (fread (header, 1, 12, magic_file) == 12)
{
if (memcmp ("MIME-Magic\0\n", header, 12) == 0)
_xdg_mime_magic_read_magic_file (mime_magic, magic_file);
}
fclose (magic_file);
}

View File

@ -0,0 +1,56 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmimemagic.h: Private file. Datastructure for storing the magic files.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2003 Red Hat, Inc.
* Copyright (C) 2003 Jonathan Blandford <jrb@alum.mit.edu>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __XDG_MIME_MAGIC_H__
#define __XDG_MIME_MAGIC_H__
#include <unistd.h>
#include "xdgmime.h"
typedef struct XdgMimeMagic XdgMimeMagic;
#ifdef XDG_PREFIX
#define _xdg_mime_glob_read_from_file XDG_ENTRY(glob_read_from_file)
#define _xdg_mime_magic_new XDG_ENTRY(magic_new)
#define _xdg_mime_magic_read_from_file XDG_ENTRY(magic_read_from_file)
#define _xdg_mime_magic_free XDG_ENTRY(magic_free)
#define _xdg_mime_magic_get_buffer_extents XDG_ENTRY(magic_get_buffer_extents)
#define _xdg_mime_magic_lookup_data XDG_ENTRY(magic_lookup_data)
#endif
XdgMimeMagic *_xdg_mime_magic_new (void);
void _xdg_mime_magic_read_from_file (XdgMimeMagic *mime_magic,
const char *file_name);
void _xdg_mime_magic_free (XdgMimeMagic *mime_magic);
int _xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic);
const char *_xdg_mime_magic_lookup_data (XdgMimeMagic *mime_magic,
const void *data,
size_t len,
const char *mime_types[],
int n_mime_types);
#endif /* __XDG_MIME_MAGIC_H__ */

219
lib/xdgmime/xdgmimeparent.c Normal file
View File

@ -0,0 +1,219 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmimealias.c: Private file. Datastructure for storing the hierarchy.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2004 Red Hat, Inc.
* Copyright (C) 2004 Matthias Clasen <mclasen@redhat.com>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "xdgmimeparent.h"
#include "xdgmimeint.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <fnmatch.h>
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
typedef struct XdgMimeParents XdgMimeParents;
struct XdgMimeParents
{
char *mime;
char **parents;
int n_parents;
};
struct XdgParentList
{
struct XdgMimeParents *parents;
int n_mimes;
};
XdgParentList *
_xdg_mime_parent_list_new (void)
{
XdgParentList *list;
list = malloc (sizeof (XdgParentList));
list->parents = NULL;
list->n_mimes = 0;
return list;
}
void
_xdg_mime_parent_list_free (XdgParentList *list)
{
int i;
char **p;
if (list->parents)
{
for (i = 0; i < list->n_mimes; i++)
{
for (p = list->parents[i].parents; *p; p++)
free (*p);
free (list->parents[i].parents);
free (list->parents[i].mime);
}
free (list->parents);
}
free (list);
}
static int
parent_entry_cmp (const void *v1, const void *v2)
{
return strcmp (((XdgMimeParents *)v1)->mime, ((XdgMimeParents *)v2)->mime);
}
const char **
_xdg_mime_parent_list_lookup (XdgParentList *list,
const char *mime)
{
XdgMimeParents *entry;
XdgMimeParents key;
if (list->n_mimes > 0)
{
key.mime = (char *)mime;
key.parents = NULL;
entry = bsearch (&key, list->parents, list->n_mimes,
sizeof (XdgMimeParents), &parent_entry_cmp);
if (entry)
return (const char **)entry->parents;
}
return NULL;
}
void
_xdg_mime_parent_read_from_file (XdgParentList *list,
const char *file_name)
{
FILE *file;
char line[255];
int i, alloc;
XdgMimeParents *entry;
file = fopen (file_name, "r");
if (file == NULL)
return;
/* FIXME: Not UTF-8 safe. Doesn't work if lines are greater than 255 chars.
* Blah */
alloc = list->n_mimes + 16;
list->parents = realloc (list->parents, alloc * sizeof (XdgMimeParents));
while (fgets (line, 255, file) != NULL)
{
char *sep;
if (line[0] == '#')
continue;
sep = strchr (line, ' ');
if (sep == NULL)
continue;
*(sep++) = '\000';
sep[strlen (sep) -1] = '\000';
entry = NULL;
for (i = 0; i < list->n_mimes; i++)
{
if (strcmp (list->parents[i].mime, line) == 0)
{
entry = &(list->parents[i]);
break;
}
}
if (!entry)
{
if (list->n_mimes == alloc)
{
alloc <<= 1;
list->parents = realloc (list->parents,
alloc * sizeof (XdgMimeParents));
}
list->parents[list->n_mimes].mime = strdup (line);
list->parents[list->n_mimes].parents = NULL;
entry = &(list->parents[list->n_mimes]);
list->n_mimes++;
}
if (!entry->parents)
{
entry->n_parents = 1;
entry->parents = malloc ((entry->n_parents + 1) * sizeof (char *));
}
else
{
entry->n_parents += 1;
entry->parents = realloc (entry->parents,
(entry->n_parents + 2) * sizeof (char *));
}
entry->parents[entry->n_parents - 1] = strdup (sep);
entry->parents[entry->n_parents] = NULL;
}
list->parents = realloc (list->parents,
list->n_mimes * sizeof (XdgMimeParents));
fclose (file);
if (list->n_mimes > 1)
qsort (list->parents, list->n_mimes,
sizeof (XdgMimeParents), &parent_entry_cmp);
}
void
_xdg_mime_parent_list_dump (XdgParentList *list)
{
int i;
char **p;
if (list->parents)
{
for (i = 0; i < list->n_mimes; i++)
{
for (p = list->parents[i].parents; *p; p++)
printf ("%s %s\n", list->parents[i].mime, *p);
}
}
}

View File

@ -0,0 +1,50 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* xdgmimeparent.h: Private file. Datastructure for storing the hierarchy.
*
* More info can be found at http://www.freedesktop.org/standards/
*
* Copyright (C) 2004 Red Hat, Inc.
* Copyright (C) 200 Matthias Clasen <mclasen@redhat.com>
*
* Licensed under the Academic Free License version 2.0
* Or under the following terms:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __XDG_MIME_PARENT_H__
#define __XDG_MIME_PARENT_H__
#include "xdgmime.h"
typedef struct XdgParentList XdgParentList;
#ifdef XDG_PREFIX
#define _xdg_mime_parent_read_from_file XDG_ENTRY(parent_read_from_file)
#define _xdg_mime_parent_list_new XDG_ENTRY(parent_list_new)
#define _xdg_mime_parent_list_free XDG_ENTRY(parent_list_free)
#define _xdg_mime_parent_list_lookup XDG_ENTRY(parent_list_lookup)
#endif
void _xdg_mime_parent_read_from_file (XdgParentList *list,
const char *file_name);
XdgParentList *_xdg_mime_parent_list_new (void);
void _xdg_mime_parent_list_free (XdgParentList *list);
const char **_xdg_mime_parent_list_lookup (XdgParentList *list,
const char *mime);
void _xdg_mime_parent_list_dump (XdgParentList *list);
#endif /* __XDG_MIME_PARENT_H__ */

2
shell/extensions/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
stamp-sugar-shell-marshal.*
sugar-shell-marshal.*

View File

@ -9,15 +9,12 @@ pkgpyexec_LTLIBRARIES = _extensions.la
_extensions_la_LDFLAGS = -module -avoid-version
_extensions_la_CFLAGS = \
$(WARN_CFLAGS) \
$(PYTHON_INCLUDES) \
$(PYGTK_CFLAGS) \
$(SHELL_CFLAGS) \
-I$(top_srcdir)/shell/extensions
_extensions_la_LIBADD = \
$(SHELL_LIBS) \
$(PYCAIRO_LIBS) \
-lgstinterfaces-0.10 \
-lgstaudio-0.10

View File

@ -1 +0,0 @@
timestamp

View File

@ -1 +0,0 @@
timestamp

View File

@ -1,104 +0,0 @@
#ifndef __sugar_shell_marshal_MARSHAL_H__
#define __sugar_shell_marshal_MARSHAL_H__
#include <glib-object.h>
G_BEGIN_DECLS
#ifdef G_ENABLE_DEBUG
#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
#define g_marshal_value_peek_char(v) g_value_get_char (v)
#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
#define g_marshal_value_peek_int(v) g_value_get_int (v)
#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
#define g_marshal_value_peek_long(v) g_value_get_long (v)
#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
#define g_marshal_value_peek_float(v) g_value_get_float (v)
#define g_marshal_value_peek_double(v) g_value_get_double (v)
#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
#define g_marshal_value_peek_param(v) g_value_get_param (v)
#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
#define g_marshal_value_peek_object(v) g_value_get_object (v)
#else /* !G_ENABLE_DEBUG */
/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
* Do not access GValues directly in your code. Instead, use the
* g_value_get_*() functions
*/
#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
#define g_marshal_value_peek_char(v) (v)->data[0].v_int
#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
#define g_marshal_value_peek_int(v) (v)->data[0].v_int
#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
#define g_marshal_value_peek_long(v) (v)->data[0].v_long
#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
#define g_marshal_value_peek_float(v) (v)->data[0].v_float
#define g_marshal_value_peek_double(v) (v)->data[0].v_double
#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
#endif /* !G_ENABLE_DEBUG */
/* BOOLEAN:UINT,UINT (./sugar-shell-marshal.list:1) */
extern void sugar_shell_marshal_BOOLEAN__UINT_UINT (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data);
void
sugar_shell_marshal_BOOLEAN__UINT_UINT (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
typedef gboolean (*GMarshalFunc_BOOLEAN__UINT_UINT) (gpointer data1,
guint arg_1,
guint arg_2,
gpointer data2);
register GMarshalFunc_BOOLEAN__UINT_UINT callback;
register GCClosure *cc = (GCClosure*) closure;
register gpointer data1, data2;
gboolean v_return;
g_return_if_fail (return_value != NULL);
g_return_if_fail (n_param_values == 3);
if (G_CCLOSURE_SWAP_DATA (closure))
{
data1 = closure->data;
data2 = g_value_peek_pointer (param_values + 0);
}
else
{
data1 = g_value_peek_pointer (param_values + 0);
data2 = closure->data;
}
callback = (GMarshalFunc_BOOLEAN__UINT_UINT) (marshal_data ? marshal_data : cc->callback);
v_return = callback (data1,
g_marshal_value_peek_uint (param_values + 1),
g_marshal_value_peek_uint (param_values + 2),
data2);
g_value_set_boolean (return_value, v_return);
}
G_END_DECLS
#endif /* __sugar_shell_marshal_MARSHAL_H__ */

View File

@ -1,20 +0,0 @@
#ifndef __sugar_shell_marshal_MARSHAL_H__
#define __sugar_shell_marshal_MARSHAL_H__
#include <glib-object.h>
G_BEGIN_DECLS
/* BOOLEAN:UINT,UINT (./sugar-shell-marshal.list:1) */
extern void sugar_shell_marshal_BOOLEAN__UINT_UINT (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data);
G_END_DECLS
#endif /* __sugar_shell_marshal_MARSHAL_H__ */

View File

@ -26,6 +26,7 @@ from sugar.activity import bundleregistry
_SERVICE_NAME = "org.laptop.Activity"
_SERVICE_PATH = "/org/laptop/Activity"
_SERVICE_INTERFACE = "org.laptop.Activity"
class HomeModel(gobject.GObject):
"""Model of the "Home" view (activity management)
@ -68,6 +69,12 @@ class HomeModel(gobject.GObject):
screen.connect('window-closed', self._window_closed_cb)
screen.connect('active-window-changed',
self._active_window_changed_cb)
bus = dbus.SessionBus()
bus.add_signal_receiver(
self._dbus_name_owner_changed_cb,
'NameOwnerChanged',
'org.freedesktop.DBus',
'org.freedesktop.DBus')
def get_current_activity(self):
return self._current_activity
@ -103,9 +110,31 @@ class HomeModel(gobject.GObject):
self.emit('active-activity-changed', None)
self._notify_activity_activation(self._current_activity, None)
def _dbus_name_owner_changed_cb(self, name, old, new):
"""Detect new activity instances on the DBus
Normally, new activities are detected by
the _window_opened_cb callback. However, if the
window is opened before the dbus service is up,
a RawHomeWindow is created. In here we create
a proper HomeActivity replacing the RawHomeWindow.
"""
if name.startswith(_SERVICE_NAME) and new and not old:
xid = name[len(_SERVICE_NAME):]
if not xid.isdigit():
return
logging.debug("Activity instance launch detected: %s" % name)
xid = int(xid)
act = self._get_activity_by_xid(xid)
if isinstance(act, HomeRawWindow):
logging.debug("Removing bogus raw activity %s for window %i"
% (act.get_activity_id(), xid))
self._internal_remove_activity(act)
self._add_activity(act.get_window())
def _get_activity_by_xid(self, xid):
for act in self._activities.values():
if act.get_xid() == xid:
if act.get_launched() and act.get_xid() == xid:
return act
return None
@ -168,8 +197,11 @@ class HomeModel(gobject.GObject):
bus = dbus.SessionBus()
xid = window.get_xid()
try:
service = bus.get_object(_SERVICE_NAME + '%d' % xid,
_SERVICE_PATH + "/%s" % xid)
service = dbus.Interface(
bus.get_object(_SERVICE_NAME + '%d' % xid,
_SERVICE_PATH + "/%s" % xid),
_SERVICE_INTERFACE)
except dbus.DBusException:
service = None

View File

@ -1,4 +1,4 @@
SUBDIRS = activity browser clipboard graphics p2p presence datastore
SUBDIRS = activity clipboard graphics objects presence datastore
sugardir = $(pythondir)/sugar
sugar_PYTHON = \
@ -9,3 +9,40 @@ sugar_PYTHON = \
ltihooks.py \
profile.py \
util.py
INCLUDES = \
$(LIB_CFLAGS) \
$(LIB_BINDINGS_CFLAGS) \
$(PYTHON_INCLUDES) \
-I$(top_srcdir)/lib \
-I$(top_srcdir)/lib/xdgmime
pkgpyexecdir = $(pythondir)/sugar
pkgpyexec_LTLIBRARIES = _sugarext.la
_sugarext_la_LDFLAGS = -module -avoid-version
_sugarext_la_LIBADD = \
$(LIB_BINDINGS_LIBS) \
$(LIB_LIBS) \
$(top_builddir)/lib/libsugar.la
_sugarext_la_SOURCES = \
_sugarextmodule.c
nodist__sugarext_la_SOURCES = _sugarext.c
_sugarext.c: _sugarext.defs _sugarext.override
CLEANFILES = _sugarext.c
EXTRA_DIST = _sugarext.override _sugarext.defs
.defs.c:
(cd $(srcdir)\
&& $(PYGTK_CODEGEN) \
--register $(PYGTK_DEFSDIR)/gdk-types.defs \
--register $(PYGTK_DEFSDIR)/gtk-types.defs \
--override $*.override \
--prefix py$* $*.defs) > gen-$*.c \
&& cp gen-$*.c $*.c \
&& rm -f gen-$*.c

152
sugar/_sugarext.c Normal file
View File

@ -0,0 +1,152 @@
/* -- THIS FILE IS GENERATED - DO NOT EDIT *//* -*- Mode: C; c-basic-offset: 4 -*- */
#include <Python.h>
#line 4 "_sugarext.override"
#include <Python.h>
#include "pygobject.h"
#include "sugar-address-entry.h"
#include "xdgmime.h"
#include <pygtk/pygtk.h>
#include <glib.h>
#line 18 "_sugarext.c"
/* ---------- types from other modules ---------- */
static PyTypeObject *_PyGtkEntry_Type;
#define PyGtkEntry_Type (*_PyGtkEntry_Type)
/* ---------- forward type declarations ---------- */
PyTypeObject G_GNUC_INTERNAL PySugarAddressEntry_Type;
#line 29 "_sugarext.c"
/* ----------- SugarAddressEntry ----------- */
PyTypeObject G_GNUC_INTERNAL PySugarAddressEntry_Type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"_sugarext.AddressEntry", /* tp_name */
sizeof(PyGObject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)0, /* tp_dealloc */
(printfunc)0, /* tp_print */
(getattrfunc)0, /* tp_getattr */
(setattrfunc)0, /* tp_setattr */
(cmpfunc)0, /* tp_compare */
(reprfunc)0, /* tp_repr */
(PyNumberMethods*)0, /* tp_as_number */
(PySequenceMethods*)0, /* tp_as_sequence */
(PyMappingMethods*)0, /* tp_as_mapping */
(hashfunc)0, /* tp_hash */
(ternaryfunc)0, /* tp_call */
(reprfunc)0, /* tp_str */
(getattrofunc)0, /* tp_getattro */
(setattrofunc)0, /* tp_setattro */
(PyBufferProcs*)0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
NULL, /* Documentation string */
(traverseproc)0, /* tp_traverse */
(inquiry)0, /* tp_clear */
(richcmpfunc)0, /* tp_richcompare */
offsetof(PyGObject, weakreflist), /* tp_weaklistoffset */
(getiterfunc)0, /* tp_iter */
(iternextfunc)0, /* tp_iternext */
(struct PyMethodDef*)NULL, /* tp_methods */
(struct PyMemberDef*)0, /* tp_members */
(struct PyGetSetDef*)0, /* tp_getset */
NULL, /* tp_base */
NULL, /* tp_dict */
(descrgetfunc)0, /* tp_descr_get */
(descrsetfunc)0, /* tp_descr_set */
offsetof(PyGObject, inst_dict), /* tp_dictoffset */
(initproc)0, /* tp_init */
(allocfunc)0, /* tp_alloc */
(newfunc)0, /* tp_new */
(freefunc)0, /* tp_free */
(inquiry)0 /* tp_is_gc */
};
/* ----------- functions ----------- */
static PyObject *
_wrap_sugar_mime_get_mime_type_from_file_name(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "filename", NULL };
char *filename;
const gchar *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,"s:get_mime_type_from_file_name", kwlist, &filename))
return NULL;
ret = sugar_mime_get_mime_type_from_file_name(filename);
if (ret)
return PyString_FromString(ret);
Py_INCREF(Py_None);
return Py_None;
}
#line 23 "_sugarext.override"
static PyObject *
_wrap_sugar_mime_get_mime_type_for_file(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "filename", NULL };
char *filename;
const gchar *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,"s:get_mime_type_for_file", kwlist, &filename))
return NULL;
ret = sugar_mime_get_mime_type_for_file(filename, NULL);
if (ret)
return PyString_FromString(ret);
Py_INCREF(Py_None);
return Py_None;
}
#line 120 "_sugarext.c"
const PyMethodDef py_sugarext_functions[] = {
{ "get_mime_type_from_file_name", (PyCFunction)_wrap_sugar_mime_get_mime_type_from_file_name, METH_VARARGS|METH_KEYWORDS,
NULL },
{ "get_mime_type_for_file", (PyCFunction)_wrap_sugar_mime_get_mime_type_for_file, METH_VARARGS|METH_KEYWORDS,
NULL },
{ NULL, NULL, 0, NULL }
};
/* initialise stuff extension classes */
void
py_sugarext_register_classes(PyObject *d)
{
PyObject *module;
if ((module = PyImport_ImportModule("gtk")) != NULL) {
_PyGtkEntry_Type = (PyTypeObject *)PyObject_GetAttrString(module, "Entry");
if (_PyGtkEntry_Type == NULL) {
PyErr_SetString(PyExc_ImportError,
"cannot import name Entry from gtk");
return ;
}
} else {
PyErr_SetString(PyExc_ImportError,
"could not import gtk");
return ;
}
#line 151 "_sugarext.c"
pygobject_register_class(d, "SugarAddressEntry", SUGAR_TYPE_ADDRESS_ENTRY, &PySugarAddressEntry_Type, Py_BuildValue("(O)", &PyGtkEntry_Type));
}

27
sugar/_sugarext.defs Normal file
View File

@ -0,0 +1,27 @@
;; -*- scheme -*-
; object definitions
(define-object AddressEntry
(in-module "Sugar")
(parent "GtkEntry")
(c-name "SugarAddressEntry")
(gtype-id "SUGAR_TYPE_ADDRESS_ENTRY")
)
; functions
(define-function get_mime_type_from_file_name
(c-name "sugar_mime_get_mime_type_from_file_name")
(return-type "const-char*")
(parameters
'("const-char*" "filename")
)
)
(define-function get_mime_type_for_file
(c-name "sugar_mime_get_mime_type_for_file")
(return-type "const-char*")
(parameters
'("const-char*" "filename")
)
)

40
sugar/_sugarext.override Normal file
View File

@ -0,0 +1,40 @@
/* -*- Mode: C; c-basic-offset: 4 -*- */
%%
headers
#include <Python.h>
#include "pygobject.h"
#include "sugar-address-entry.h"
#include "xdgmime.h"
#include <pygtk/pygtk.h>
#include <glib.h>
%%
modulename _sugarext
%%
import gtk.Entry as PyGtkEntry_Type
%%
ignore-glob
*_get_type
_*
%%
override sugar_mime_get_mime_type_for_file kwargs
static PyObject *
_wrap_sugar_mime_get_mime_type_for_file(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "filename", NULL };
char *filename;
const gchar *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,"s:get_mime_type_for_file", kwlist, &filename))
return NULL;
ret = sugar_mime_get_mime_type_for_file(filename, NULL);
if (ret)
return PyString_FromString(ret);
Py_INCREF(Py_None);
return Py_None;
}
%%

27
sugar/_sugarextmodule.c Normal file
View File

@ -0,0 +1,27 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* include this first, before NO_IMPORT_PYGOBJECT is defined */
#include <pygobject.h>
void py_sugarext_register_classes (PyObject *d);
extern PyMethodDef py_sugarext_functions[];
DL_EXPORT(void)
init_sugarext(void)
{
PyObject *m, *d;
init_pygobject ();
m = Py_InitModule ("_sugarext", py_sugarext_functions);
d = PyModule_GetDict (m);
py_sugarext_register_classes (d);
if (PyErr_Occurred ()) {
Py_FatalError ("can't initialise module _sugarext");
}
}

View File

@ -31,6 +31,8 @@ _ACTIVITY_SERVICE_NAME = "org.laptop.Activity"
_ACTIVITY_SERVICE_PATH = "/org/laptop/Activity"
_ACTIVITY_INTERFACE = "org.laptop.Activity"
_ACTIVITY_FACTORY_INTERFACE = "org.laptop.ActivityFactory"
def create_activity_id():
"""Generate a new, unique ID for this activity"""
pservice = presenceservice.get_instance()
@ -103,7 +105,7 @@ class ActivityCreationHandler(gobject.GObject):
bus = dbus.SessionBus()
proxy_obj = bus.get_object(service_name, bundle.get_object_path(), follow_name_owner_changes=True)
factory = dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityFactory")
factory = dbus.Interface(proxy_obj, _ACTIVITY_FACTORY_INTERFACE)
factory.create(self._activity_handle.get_dict(),
reply_handler=self._reply_handler,

View File

@ -34,6 +34,8 @@ from sugar import logger
gobject.threads_init()
dbus.glib.threads_init()
_ACTIVITY_FACTORY_INTERFACE = "org.laptop.ActivityFactory"
class ActivityFactoryService(dbus.service.Object):
"""D-Bus service that creates instances of Python activities
@ -92,7 +94,7 @@ class ActivityFactoryService(dbus.service.Object):
object_path = '/' + service_name.replace('.', '/')
dbus.service.Object.__init__(self, bus_name, object_path)
@dbus.service.method("com.redhat.Sugar.ActivityFactory", in_signature="a{ss}")
@dbus.service.method("org.laptop.ActivityFactory", in_signature="a{ss}")
def create(self, handle):
"""Create a new instance of this activity

View File

@ -1,47 +0,0 @@
sugardir = $(pythondir)/sugar/browser
sugar_PYTHON = \
__init__.py
INCLUDES = \
$(PYTHON_INCLUDES) \
$(PYGTK_CFLAGS) \
$(PYCAIRO_CFLAGS) \
$(LIB_CFLAGS) \
$(GECKO_CFLAGS) \
$(NSPR_CFLAGS) \
-I$(MOZILLA_INCLUDE_DIR)/gtkembedmoz \
-I$(top_srcdir)/browser
pkgpyexecdir = $(pythondir)/sugar/browser
pkgpyexec_LTLIBRARIES = _sugarbrowser.la
_sugarbrowser_la_LDFLAGS = -module -avoid-version $(GECKO_LDFLAGS)
_sugarbrowser_la_LIBADD = \
$(LIB_LIBS) \
$(PYCAIRO_LIBS) \
$(GECKO_LIBS) \
$(XPCOMGLUE_LIBS) \
$(top_builddir)/browser/libsugarbrowser.la
_sugarbrowser_la_SOURCES = \
_sugarbrowsermodule.c \
xulrunner.cpp \
xulrunner.h
nodist__sugarbrowser_la_SOURCES = _sugarbrowser.c
_sugar.c: _sugarbrowser.defs gtkmozembed.defs _sugarbrowser.override gtkmozembed.override
CLEANFILES = _sugarbrowser.c
EXTRA_DIST = _sugarbrowser.override _sugarbrowser.defs gtkmozembed.defs gtkmozembed.override
.defs.c:
(cd $(srcdir)\
&& $(PYGTK_CODEGEN) \
--register $(PYGTK_DEFSDIR)/gdk-types.defs \
--register $(PYGTK_DEFSDIR)/gtk-types.defs \
--override $*.override \
--prefix py$* $*.defs) > gen-$*.c \
&& cp gen-$*.c $*.c \
&& rm -f gen-$*.c

View File

@ -1,31 +0,0 @@
"""Sugar's web-browser activity
XUL Runner and gtkmozembed and is produced by the PyGTK
.defs system.
"""
try:
from sugar.browser import _sugarbrowser
except ImportError:
from sugar import ltihooks
from sugar.browser import _sugarbrowser
from _sugarbrowser import AddressEntry
from _sugarbrowser import startup, shutdown, get_download_manager
class Browser(_sugarbrowser.Browser):
def __init__(self):
_sugarbrowser.Browser.__init__(self)
def get_browser(self):
from xpcom import components
cls = components.classes["@laptop.org/browser/browserhelper;1"]
browser_helper = cls.getService(components.interfaces.nsIBrowserHelper)
print self.get_instance_id()
return browser_helper.getBrowser(self.get_instance_id())
def get_document(self):
return self.browser.contentDOMWindow.document
document = property(get_document)
browser = property(get_browser)

View File

@ -1,206 +0,0 @@
;; -*- scheme -*-
; object definitions ...
(define-boxed SugarBrowserEvent
(in-module "Sugar")
(c-name "SugarBrowserEvent")
(gtype-id "SUGAR_TYPE_BROWSER_EVENT")
(copy-func "sugar_browser_event_copy")
(release-func "sugar_browser_event_free")
)
(define-boxed SugarBrowserMetadata
(in-module "Sugar")
(c-name "SugarBrowserMetadata")
(gtype-id "SUGAR_TYPE_BROWSER_METADATA")
(copy-func "sugar_browser_metadata_copy")
(release-func "sugar_browser_metadata_free")
)
(define-object AddressEntry
(in-module "Sugar")
(parent "GtkEntry")
(c-name "SugarAddressEntry")
(gtype-id "SUGAR_TYPE_ADDRESS_ENTRY")
)
(define-object Browser
(in-module "Sugar")
(parent "GtkMozEmbed")
(c-name "SugarBrowser")
(gtype-id "SUGAR_TYPE_BROWSER")
)
(define-object DownloadManager
(in-module "Sugar")
(parent "GObject")
(c-name "SugarDownloadManager")
(gtype-id "SUGAR_TYPE_DOWNLOAD_MANAGER")
)
(define-object Download
(in-module "Sugar")
(parent "GObject")
(c-name "SugarDownload")
(gtype-id "SUGAR_TYPE_DOWNLOAD")
)
;; Enumerations and flags ...
;; From sugar-address-entry.h
(define-function sugar_address_entry_get_type
(c-name "sugar_address_entry_get_type")
(return-type "GType")
)
;; From sugar-browser.h
(define-function sugar_browser_get_type
(c-name "sugar_browser_get_type")
(return-type "GType")
)
(define-function startup
(c-name "sugar_browser_startup")
(parameters
'("const-char*" "profile_path")
'("const-char*" "profile_name")
)
(return-type "gboolean")
)
(define-function shutdown
(c-name "sugar_browser_shutdown")
(return-type "none")
)
(define-method grab_focus
(of-object "SugarBrowser")
(c-name "sugar_browser_grab_focus")
(return-type "none")
)
(define-method save_uri
(of-object "SugarBrowser")
(c-name "sugar_browser_save_uri")
(return-type "gboolean")
(parameters
'("const-char*" "uri")
'("const-char*" "filename")
)
)
(define-method save_document
(of-object "SugarBrowser")
(c-name "sugar_browser_save_document")
(return-type "gboolean")
(parameters
'("const-char*" "filename")
)
)
(define-method create_window
(of-object "SugarBrowser")
(c-name "sugar_browser_create_window")
(return-type "SugarBrowser*")
)
(define-virtual create_window
(of-object "SugarBrowser")
(c-name "sugar_browser_create_window")
(return-type "SugarBrowser*")
)
(define-method get_session
(of-object "SugarBrowser")
(c-name "sugar_browser_get_session")
(return-type "char*")
)
(define-method set_session
(of-object "SugarBrowser")
(c-name "sugar_browser_set_session")
(return-type "none")
(parameters
'("const-char*" "session")
)
)
(define-method get_instance_id
(of-object "SugarBrowser")
(c-name "sugar_browser_get_instance_id")
(return-type "int")
)
;; From sugar-key-grabber.h
(define-function sugar_key_grabber_get_type
(c-name "sugar_key_grabber_get_type")
(return-type "GType")
)
(define-method grab
(of-object "SugarKeyGrabber")
(c-name "sugar_key_grabber_grab")
(return-type "none")
(parameters
'("const-char*" "key")
)
)
(define-method get_key
(of-object "SugarKeyGrabber")
(c-name "sugar_key_grabber_get_key")
(return-type "char*")
(parameters
'("guint" "keycode")
'("guint" "state")
)
)
;; From sugar-download-manager.h
(define-function sugar_download_manager_get_type
(c-name "sugar_download_manager_get_type")
(return-type "GType")
)
(define-function get_download_manager
(c-name "sugar_get_download_manager")
(return-type "SugarDownloadManager*")
)
;; From sugar-download.h
(define-function sugar_download_get_type
(c-name "sugar_download_get_type")
(return-type "GType")
)
(define-method get_file_name
(of-object "SugarDownload")
(c-name "sugar_download_get_file_name")
(return-type "const-gchar*")
)
(define-method get_url
(of-object "SugarDownload")
(c-name "sugar_download_get_url")
(return-type "const-gchar*")
)
(define-method get_mime_type
(of-object "SugarDownload")
(c-name "sugar_download_get_mime_type")
(return-type "const-gchar*")
)
(define-method get_percent
(of-object "SugarDownload")
(c-name "sugar_download_get_percent")
(return-type "gint")
)
(include "gtkmozembed.defs")

View File

@ -1,80 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4 -*- */
%%
headers
#include <Python.h>
#include "pygobject.h"
#include "sugar-browser.h"
#include "sugar-address-entry.h"
#include "sugar-download-manager.h"
#include "sugar-download.h"
#include <pygtk/pygtk.h>
#include <glib.h>
%%
modulename _sugarbrowser
%%
import gobject.GObject as PyGObject_Type
import gtk.Entry as PyGtkEntry_Type
import gtk.gdk.Screen as PyGdkScreen_Type
import gtk.gdk.Pixbuf as PyGdkPixbuf_Type
import hippo.CanvasImage as HippoCanvasImage_Type
%%
ignore-glob
*_get_type
_*
%%
include
gtkmozembed.override
%%
override-slot SugarBrowserMetadata.tp_getattr
static PyObject *
_wrap_sugar_browser_metadata_tp_getattr(PyObject *self, char *attr)
{
SugarBrowserMetadata *metadata = pyg_boxed_get(self, SugarBrowserMetadata);
if (!strcmp(attr, "__members__"))
return Py_BuildValue("[s]", "filename");
else if (!strcmp(attr, "filename")) {
if (metadata->filename) {
return PyString_FromString(metadata->filename);
} else {
Py_INCREF(Py_None);
return Py_None;
}
}
return NULL;
}
%%
override-slot SugarBrowserEvent.tp_getattr
static PyObject *
_wrap_sugar_browser_event_tp_getattr(PyObject *self, char *attr)
{
SugarBrowserEvent *event = pyg_boxed_get(self, SugarBrowserEvent);
if (!strcmp(attr, "__members__"))
return Py_BuildValue("[sss]", "image_uri", "button", "image_name");
else if (!strcmp(attr, "image_uri")) {
if (event->image_uri) {
return PyString_FromString(event->image_uri);
} else {
Py_INCREF(Py_None);
return Py_None;
}
}
else if (!strcmp(attr, "image_name")) {
if (event->image_name) {
return PyString_FromString(event->image_name);
} else {
Py_INCREF(Py_None);
return Py_None;
}
}
else if (!strcmp(attr, "button"))
return PyInt_FromLong(event->button);
return NULL;
}
%%

View File

@ -1,32 +0,0 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xulrunner.h"
/* include this first, before NO_IMPORT_PYGOBJECT is defined */
#include <pygobject.h>
void py_sugarbrowser_register_classes (PyObject *d);
extern PyMethodDef py_sugarbrowser_functions[];
DL_EXPORT(void)
init_sugarbrowser(void)
{
PyObject *m, *d;
xulrunner_startup();
init_pygobject ();
m = Py_InitModule ("_sugarbrowser", py_sugarbrowser_functions);
d = PyModule_GetDict (m);
py_sugarbrowser_register_classes (d);
py_sugarbrowser_add_constants(m, "GTK_MOZ_EMBED_");
if (PyErr_Occurred ()) {
Py_FatalError ("can't initialise module _sugarbrowser");
}
}

View File

@ -1 +0,0 @@

View File

@ -1,475 +0,0 @@
;; -*- scheme -*-
; object definitions ...
(define-object MozEmbed
(in-module "Gtk")
(parent "GtkBin")
(c-name "GtkMozEmbed")
(gtype-id "GTK_TYPE_MOZ_EMBED")
)
; (define-object MozEmbedSingle
; (in-module "Gtk")
; (parent "GtkObject")
; (c-name "GtkMozEmbedSingle")
; (gtype-id "GTK_TYPE_MOZ_EMBED_SINGLE")
; )
;; Enumerations and flags ...
(define-enum MozEmbedProgressFlags
(in-module "Gtk")
(c-name "GtkMozEmbedProgressFlags")
(values
'("start" "GTK_MOZ_EMBED_FLAG_START")
'("redirecting" "GTK_MOZ_EMBED_FLAG_REDIRECTING")
'("transferring" "GTK_MOZ_EMBED_FLAG_TRANSFERRING")
'("negotiating" "GTK_MOZ_EMBED_FLAG_NEGOTIATING")
'("stop" "GTK_MOZ_EMBED_FLAG_STOP")
'("is-request" "GTK_MOZ_EMBED_FLAG_IS_REQUEST")
'("is-document" "GTK_MOZ_EMBED_FLAG_IS_DOCUMENT")
'("is-network" "GTK_MOZ_EMBED_FLAG_IS_NETWORK")
'("is-window" "GTK_MOZ_EMBED_FLAG_IS_WINDOW")
)
)
(define-enum MozEmbedStatusFlags
(in-module "Gtk")
(c-name "GtkMozEmbedStatusFlags")
(values
'("dns" "GTK_MOZ_EMBED_STATUS_FAILED_DNS")
'("connect" "GTK_MOZ_EMBED_STATUS_FAILED_CONNECT")
'("timeout" "GTK_MOZ_EMBED_STATUS_FAILED_TIMEOUT")
'("usercanceled" "GTK_MOZ_EMBED_STATUS_FAILED_USERCANCELED")
)
)
(define-enum MozEmbedReloadFlags
(in-module "Gtk")
(c-name "GtkMozEmbedReloadFlags")
(values
'("normal" "GTK_MOZ_EMBED_FLAG_RELOADNORMAL")
'("bypasscache" "GTK_MOZ_EMBED_FLAG_RELOADBYPASSCACHE")
'("bypassproxy" "GTK_MOZ_EMBED_FLAG_RELOADBYPASSPROXY")
'("bypassproxyandcache" "GTK_MOZ_EMBED_FLAG_RELOADBYPASSPROXYANDCACHE")
'("charsetchange" "GTK_MOZ_EMBED_FLAG_RELOADCHARSETCHANGE")
)
)
(define-enum MozEmbedChromeFlags
(in-module "Gtk")
(c-name "GtkMozEmbedChromeFlags")
(values
'("defaultchrome" "GTK_MOZ_EMBED_FLAG_DEFAULTCHROME")
'("windowborderson" "GTK_MOZ_EMBED_FLAG_WINDOWBORDERSON")
'("windowcloseon" "GTK_MOZ_EMBED_FLAG_WINDOWCLOSEON")
'("windowresizeon" "GTK_MOZ_EMBED_FLAG_WINDOWRESIZEON")
'("menubaron" "GTK_MOZ_EMBED_FLAG_MENUBARON")
'("toolbaron" "GTK_MOZ_EMBED_FLAG_TOOLBARON")
'("locationbaron" "GTK_MOZ_EMBED_FLAG_LOCATIONBARON")
'("statusbaron" "GTK_MOZ_EMBED_FLAG_STATUSBARON")
'("personaltoolbaron" "GTK_MOZ_EMBED_FLAG_PERSONALTOOLBARON")
'("scrollbarson" "GTK_MOZ_EMBED_FLAG_SCROLLBARSON")
'("titlebaron" "GTK_MOZ_EMBED_FLAG_TITLEBARON")
'("extrachromeon" "GTK_MOZ_EMBED_FLAG_EXTRACHROMEON")
'("allchrome" "GTK_MOZ_EMBED_FLAG_ALLCHROME")
'("windowraised" "GTK_MOZ_EMBED_FLAG_WINDOWRAISED")
'("windowlowered" "GTK_MOZ_EMBED_FLAG_WINDOWLOWERED")
'("centerscreen" "GTK_MOZ_EMBED_FLAG_CENTERSCREEN")
'("dependent" "GTK_MOZ_EMBED_FLAG_DEPENDENT")
'("modal" "GTK_MOZ_EMBED_FLAG_MODAL")
'("openasdialog" "GTK_MOZ_EMBED_FLAG_OPENASDIALOG")
'("openaschrome" "GTK_MOZ_EMBED_FLAG_OPENASCHROME")
)
)
;; From /usr/include/mozilla-1.2b/gtkembedmoz/gtkmozembed.h
(define-function gtk_moz_embed_get_type
(c-name "gtk_moz_embed_get_type")
(return-type "GtkType")
)
(define-function gtk_moz_embed_new
(c-name "gtk_moz_embed_new")
(is-constructor-of "GtkMozEmbed")
(return-type "GtkWidget*")
)
(define-function push_startup
(c-name "gtk_moz_embed_push_startup")
(return-type "none")
)
(define-function pop_startup
(c-name "gtk_moz_embed_pop_startup")
(return-type "none")
)
(define-function gtk_moz_embed_set_comp_path
(c-name "gtk_moz_embed_set_comp_path_deprecated")
(return-type "none")
(parameters
'("char*" "aPath")
)
(deprecated "renamed to gtkmozembed.set_comp_path")
)
(define-function set_comp_path
(c-name "gtk_moz_embed_set_comp_path")
(return-type "none")
(parameters
'("char*" "aPath")
)
)
(define-function gtk_moz_embed_set_profile_path
(c-name "gtk_moz_embed_set_profile_path_deprecated")
(return-type "none")
(parameters
'("char*" "aDir")
'("char*" "aName")
)
(deprecated "renamed to gtkmozembed.set_profile_path")
)
(define-function set_profile_path
(c-name "gtk_moz_embed_set_profile_path")
(return-type "none")
(parameters
'("char*" "aDir")
'("char*" "aName")
)
)
(define-method load_url
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_load_url")
(return-type "none")
(parameters
'("const-char*" "url")
)
)
(define-method stop_load
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_stop_load")
(return-type "none")
)
(define-method can_go_back
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_can_go_back")
(return-type "gboolean")
)
(define-method can_go_forward
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_can_go_forward")
(return-type "gboolean")
)
(define-method go_back
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_go_back")
(return-type "none")
)
(define-method go_forward
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_go_forward")
(return-type "none")
)
(define-method render_data
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_render_data")
(return-type "none")
(parameters
'("const-char*" "data")
'("guint32" "len")
'("const-char*" "base_uri")
'("const-char*" "mime_type")
)
)
(define-method open_stream
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_open_stream")
(return-type "none")
(parameters
'("const-char*" "base_uri")
'("const-char*" "mime_type")
)
)
(define-method append_data
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_append_data")
(return-type "none")
(parameters
'("const-char*" "data")
'("guint32" "len")
)
)
(define-method close_stream
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_close_stream")
(return-type "none")
)
(define-method get_link_message
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_get_link_message")
(return-type "char*")
)
(define-method get_js_status
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_get_js_status")
(return-type "char*")
)
(define-method get_title
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_get_title")
(return-type "char*")
)
(define-method get_location
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_get_location")
(return-type "char*")
)
(define-method reload
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_reload")
(return-type "none")
(parameters
'("gint32" "flags")
)
)
(define-method set_chrome_mask
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_set_chrome_mask")
(return-type "none")
(parameters
'("guint32" "flags")
)
)
(define-method get_chrome_mask
(of-object "GtkMozEmbed")
(c-name "gtk_moz_embed_get_chrome_mask")
(return-type "guint32")
)
; (define-function gtk_moz_embed_progress_flags_get_type
; (c-name "gtk_moz_embed_progress_flags_get_type")
; (return-type "GtkType")
; )
; (define-function gtk_moz_embed_status_enums_get_type
; (c-name "gtk_moz_embed_status_enums_get_type")
; (return-type "GtkType")
; )
; (define-function gtk_moz_embed_reload_flags_get_type
; (c-name "gtk_moz_embed_reload_flags_get_type")
; (return-type "GtkType")
; )
; (define-function gtk_moz_embed_chrome_flags_get_type
; (c-name "gtk_moz_embed_chrome_flags_get_type")
; (return-type "GtkType")
; )
(define-function gtk_moz_embed_single_get
(c-name "gtk_moz_embed_single_get")
(return-type "GtkMozEmbedSingle*")
)
(define-virtual link_message
(of-object "GtkMozEmbed")
(return-type "none")
)
(define-virtual js_status
(of-object "GtkMozEmbed")
(return-type "none")
)
(define-virtual location
(of-object "GtkMozEmbed")
(return-type "none")
)
(define-virtual title
(of-object "GtkMozEmbed")
(return-type "none")
)
(define-virtual progress
(of-object "GtkMozEmbed")
(return-type "none")
(parameters
'("gint" "curprogress")
'("gint" "maxprogress")
)
)
(define-virtual progress_all
(of-object "GtkMozEmbed")
(return-type "none")
(parameters
'("const-char*" "aURI")
'("gint" "curprogress")
'("gint" "maxprogress")
)
)
(define-virtual net_state
(of-object "GtkMozEmbed")
(return-type "none")
(parameters
'("gint" "state")
'("guint" "status")
)
)
(define-virtual net_state_all
(of-object "GtkMozEmbed")
(return-type "none")
(parameters
'("const-char*" "aURI")
'("gint" "state")
'("guint" "status")
)
)
(define-virtual net_start
(of-object "GtkMozEmbed")
(return-type "none")
)
(define-virtual net_stop
(of-object "GtkMozEmbed")
(return-type "none")
)
(define-virtual new_window
(of-object "GtkMozEmbed")
(return-type "none")
(parameters
'("GtkMozEmbed**" "newEmbed")
'("guint" "chromemask")
)
)
(define-virtual visibility
(of-object "GtkMozEmbed")
(return-type "none")
(parameters
'("gboolean" "visibility")
)
)
(define-virtual destroy_brsr
(of-object "GtkMozEmbed")
(return-type "none")
)
(define-virtual open_uri
(of-object "GtkMozEmbed")
(return-type "gint")
(parameters
'("const-char*" "aURI")
)
)
(define-virtual size_to
(of-object "GtkMozEmbed")
(return-type "none")
(parameters
'("gint" "width")
'("gint" "height")
)
)
(define-virtual dom_key_down
(of-object "GtkMozEmbed")
(return-type "gint")
(parameters
'("gpointer" "dom_event")
)
)
(define-virtual dom_key_press
(of-object "GtkMozEmbed")
(return-type "gint")
(parameters
'("gpointer" "dom_event")
)
)
(define-virtual dom_key_up
(of-object "GtkMozEmbed")
(return-type "gint")
(parameters
'("gpointer" "dom_event")
)
)
(define-virtual dom_mouse_down
(of-object "GtkMozEmbed")
(return-type "gint")
(parameters
'("gpointer" "dom_event")
)
)
(define-virtual dom_mouse_up
(of-object "GtkMozEmbed")
(return-type "gint")
(parameters
'("gpointer" "dom_event")
)
)
(define-virtual dom_mouse_click
(of-object "GtkMozEmbed")
(return-type "gint")
(parameters
'("gpointer" "dom_event")
)
)
(define-virtual dom_mouse_dbl_click
(of-object "GtkMozEmbed")
(return-type "gint")
(parameters
'("gpointer" "dom_event")
)
)
(define-virtual dom_mouse_over
(of-object "GtkMozEmbed")
(return-type "gint")
(parameters
'("gpointer" "dom_event")
)
)
(define-virtual dom_mouse_out
(of-object "GtkMozEmbed")
(return-type "gint")
(parameters
'("gpointer" "dom_event")
)
)
(define-virtual security_change
(of-object "GtkMozEmbed")
(return-type "none")
(parameters
'("gpointer" "request")
'("guint" "state")
)
)
(define-virtual status_change
(of-object "GtkMozEmbed")
(return-type "none")
(parameters
'("gpointer" "request")
'("gint" "status")
'("gpointer" "message")
)
)
(define-virtual new_window_orphan
(of-object "GtkMozEmbedSingle")
(return-type "none")
(parameters
'("GtkMozEmbed**" "newEmbed")
'("guint" "chromemask")
)
)

View File

@ -1,50 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4 -*- */
%%
headers
#include <Python.h>
#define NO_IMPORT_PYGOBJECT
#include <pygobject.h>
#include <gtkmozembed.h>
%%
import gobject.GObject as PyGObject_Type
import gtk.Object as PyGtkObject_Type
import gtk.Bin as PyGtkBin_Type
%%
ignore-glob
*_get_type
_*
%%
override gtk_moz_embed_set_comp_path_deprecated kwargs
static PyObject *
_wrap_gtk_moz_embed_set_comp_path_deprecated(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "aPath", NULL };
char *aPath;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:gtk_moz_embed_set_comp_path", kwlist, &aPath))
return NULL;
if (PyErr_Warn(PyExc_DeprecationWarning, "renamed to gtkmozembed.set_comp_path") < 0)
return NULL;
gtk_moz_embed_set_comp_path(aPath);
Py_INCREF(Py_None);
return Py_None;
}
%%
override gtk_moz_embed_set_profile_path_deprecated kwargs
static PyObject *
_wrap_gtk_moz_embed_set_profile_path_deprecated(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "aDir", "aName", NULL };
char *aDir, *aName;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss:gtk_moz_embed_set_profile_path", kwlist, &aDir, &aName))
return NULL;
if (PyErr_Warn(PyExc_DeprecationWarning, "renamed to gtkmozembed.set_profile_path") < 0)
return NULL;
gtk_moz_embed_set_profile_path(aDir, aName);
Py_INCREF(Py_None);
return Py_None;
}

View File

@ -1,60 +0,0 @@
/*
* Copyright (C) 2006, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <config.h>
#include <string.h>
#include "gtkmozembed_glue.cpp"
extern "C" int
xulrunner_startup(void)
{
static const GREVersionRange greVersion = {
"1.9a", PR_TRUE,
"2", PR_TRUE
};
char xpcomPath[PATH_MAX];
nsresult rv = GRE_GetGREPathWithProperties(&greVersion, 1, nsnull, 0,
xpcomPath, sizeof(xpcomPath));
if (NS_FAILED(rv)) {
fprintf(stderr, "Couldn't find a compatible GRE.\n");
return 1;
}
rv = XPCOMGlueStartup(xpcomPath);
if (NS_FAILED(rv)) {
fprintf(stderr, "Couldn't start XPCOM.");
return 1;
}
rv = GTKEmbedGlueStartup();
if (NS_FAILED(rv)) {
fprintf(stderr, "Couldn't find GTKMozEmbed symbols.");
return 1;
}
char *lastSlash = strrchr(xpcomPath, '/');
if (lastSlash)
*lastSlash = '\0';
gtk_moz_embed_set_path(xpcomPath);
}

View File

@ -1,20 +0,0 @@
/*
* Copyright (C) 2006, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
int xulrunner_startup (void);

View File

@ -25,7 +25,7 @@ class DSObject(gobject.GObject):
([]))
}
def __init__(self, object_id, metadata, file_path):
def __init__(self, object_id, metadata=None, file_path=None):
gobject.GObject.__init__(self)
self.object_id = object_id
self._metadata = metadata
@ -43,6 +43,8 @@ class DSObject(gobject.GObject):
del self.metadata[key]
def get_metadata(self):
if self._metadata is None and not self.object_id is None:
self.set_metadata(dbus_helpers.get_properties(self.object_id))
return self._metadata
def set_metadata(self, metadata):
@ -53,6 +55,8 @@ class DSObject(gobject.GObject):
metadata = property(get_metadata, set_metadata)
def get_file_path(self):
if self._file_path is None and not self.object_id is None:
self.set_file_path(dbus_helpers.get_filename(self.object_id))
return self._file_path
def set_file_path(self, file_path):
@ -88,9 +92,30 @@ def write(ds_object, reply_handler=None, error_handler=None):
# TODO: register the object for updates
logging.debug('Written object %s to the datastore.' % ds_object.object_id)
def find(query, reply_handler=None, error_handler=None):
object_ids = dbus_helpers.find(query, reply_handler, error_handler)
def find(query, sorting=None, limit=None, offset=None, reply_handler=None,
error_handler=None):
if sorting:
query['order_by'] = sorting
if limit:
query['limit'] = limit
if offset:
query['offset'] = offset
props_list, total_count = dbus_helpers.find(query, reply_handler, error_handler)
objects = []
for object_id in object_ids:
objects.append(get(object_id))
return objects
for props in props_list:
if props.has_key('filename') and props['filename']:
file_path = props['filename']
del props['filename']
else:
file_path = None
object_id = props['uid']
del props['uid']
ds_object = DSObject(object_id, props, file_path)
objects.append(ds_object)
return objects, total_count

View File

@ -1 +1,7 @@
"""Hippo-based graphics/controls for use in Sugar"""
"""Graphics/controls for use in Sugar"""
try:
from sugar._sugarext import AddressEntry
except ImportError:
from sugar import ltihooks
from sugar._sugarext import AddressEntry

View File

@ -19,6 +19,8 @@ import logging
import gobject
import gtk
from sugar.graphics import units
class ComboBox(gtk.ComboBox):
__gtype_name__ = 'SugarComboBox'
@ -51,6 +53,7 @@ class ComboBox(gtk.ComboBox):
def append_item(self, action_id, text, icon_name=None):
if not self._icon_renderer and icon_name:
self._icon_renderer = gtk.CellRendererPixbuf()
self._icon_renderer.props.stock_size = units.microgrid_to_pixels(3)
self.pack_start(self._icon_renderer, False)
self.add_attribute(self._icon_renderer, 'icon-name', 2)

View File

@ -82,6 +82,9 @@ class StderrCatcher:
_log_writer.write(STDERR_LEVEL, txt)
sys.__stderr__.write(txt)
def flush(self):
sys.__stderr__.flush()
def __exception_handler(typ, exc, tb):
trace = StringIO()
traceback.print_exception(typ, exc, tb, None, trace)

View File

@ -1,5 +1,4 @@
sugardir = $(pythondir)/sugar/objects
sugar_PYTHON = \
__init__.py \
typeregistry.py \
typeinfo.py
mime.py

View File

@ -0,0 +1 @@
from sugar.objects import mime

11
sugar/objects/mime.py Normal file
View File

@ -0,0 +1,11 @@
try:
from sugar import _sugarext
except ImportError:
from sugar import ltihooks
from sugar import _sugarext
def get_for_file(file_name):
return _sugarext.get_mime_type_for_file(file_name)
def get_from_file_name(file_name):
return _sugarext.get_mime_type_from_file_name(file_name)

View File

@ -1,58 +0,0 @@
# Copyright (C) 2007, Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
class TypeInfo(object):
def __init__(self, info_dict=None):
self.type_id = None
self.name = None
self.icon = 'theme:stock-missing'
self.parent = None
self.formats = []
if info_dict:
self._read_from_dict(info_dict)
def get_default_activity(self):
return None
def get_activities(self):
return []
def _read_from_config(self, section, items, l_items):
self.type_id = section
for item in items:
if item[0] == 'name':
self.name = item[1]
elif item[0] == 'icon':
self.icon = item[1]
elif item[0] == 'parent':
self.parent = item[1]
elif item[0] == 'formats':
self.formats = item[1].split(';')
for item in litems:
if item[0] == 'name':
self.name = item[1]
return (self.name and self.parent and self.formats)
def _read_from_dict(self, info_dict):
self.type_id = info_dict['type_id']
self.name = info_dict['name']
self.icon = info_dict['icon']
self.formats = info_dict['formats']

View File

@ -1,99 +0,0 @@
# Copyright (C) 2007, Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
from gettext import gettext as _
from ConfigParser import ConfigParser
from sugar.objects.typeinfo import TypeInfo
from sugar.activity import bundleregistry
_text_type = {
'type_id' : 'Text',
'name' : _('Text'),
'icon' : 'theme:object-text',
'formats' : [ 'text/plain', 'application/pdf' ]
}
_image_type = {
'type_id' : 'Image',
'name' : _('Image'),
'icon' : 'theme:object-image',
'formats' : [ 'image/jpeg', 'image/gif', 'image/png' ]
}
class _RootNode(_TypeNode):
def __init__(self):
_TypeNode.__init__('')
def append_primitive(self, info_dict):
self.append(TypeInfo(info_dict))
class _TypeNode(list):
def __init__(self, type_info):
self.type_info = type_info
def get_node_from_type(self, type_id):
for node in self:
if node.type_info.type_id == type_id:
return node
for node in self:
child = node.get_node_from_type()
if child:
return child
return None
class TypeRegistry(object):
def __init__(self):
self._tree = _RootNode()
self._tree.append_primitive(_image_type)
self._tree.append_primitive(_text_type)
self._bundle_registry = bundleregistry.get_registry()
for bundle in self._bundle_registry:
self._read_from_bundle(bundle)
self._bundle_registry.connect('bundle-added', self._bundle_added_cb)
def _bundle_added_cb (self, registry, bundle):
self._read_from_bundle(bundle)
def _read_from_bundle(self, bundle):
cp = ConfigParser()
path = bundle.get_path()
cp.read([os.path.join(path, 'activity', 'object_types.info')])
items = cp.items()
cp = ConfigParser()
path = bundle.get_locale_path()
cp.read([os.path.join(path, 'object_types.linfo')])
l_items = cp.items()
for section in cp.sections():
type_info = TypeInfo()
if type_info.read_from_config(section, items, l_items):
parent_node = self._tree.get_node_from_type(type_info.parent)
if parent_node:
parent_node.append(_TypeNode(type_info))
return True
return False
def get_registry():
return _type_registry
_type_registry = TypeRegistry()

View File

@ -1,8 +0,0 @@
sugardir = $(pythondir)/sugar/p2p
sugar_PYTHON = \
__init__.py \
NotificationListener.py \
Notifier.py \
Stream.py \
MostlyReliablePipe.py \
network.py

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +0,0 @@
# Copyright (C) 2006, Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
import logging
from sugar.p2p.Notifier import Notifier
from sugar.p2p import network
class NotificationListener:
def __init__(self, service):
logging.debug('Start notification listener. Service %s, address %s, port %s' % (service.get_type(), service.get_address(), service.get_port()))
server = network.GroupServer(service.get_address(),
service.get_port(),
self._recv_multicast)
server.start()
self._listeners = []
def add_listener(self, listener):
self._listeners.append(listener)
def _recv_multicast(self, msg):
for listener in self._listeners:
listener(msg)

View File

@ -1,27 +0,0 @@
# Copyright (C) 2006, Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
from sugar.p2p import network
class Notifier:
def __init__(self, service):
address = service.get_address()
port = service.get_port()
self._client = network.GroupClient(address, port)
def notify(self, msg):
self._client.send_msg(msg)

View File

@ -1,160 +0,0 @@
# Copyright (C) 2006, Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
import xmlrpclib
import socket
import traceback
import random
import logging
import network
from MostlyReliablePipe import MostlyReliablePipe
from sugar.presence import Service
def is_multicast_address(address):
"""Simple numerical check for whether an IP4 address
is in the range for multicast addresses or not."""
if not address:
return False
if address[3] != '.':
return False
first = int(float(address[:3]))
if first >= 224 and first <= 239:
return True
return False
class Stream(object):
def __init__(self, service):
if not service.get_port():
raise ValueError("service must have an address.")
self._service = service
self._reader_port = self._service.get_port()
self._writer_port = self._reader_port
self._address = self._service.get_address()
self._callback = None
def new_from_service(service, start_reader=True):
if is_multicast_address(service.get_address()):
return MulticastStream(service)
else:
return UnicastStream(service, start_reader)
new_from_service = staticmethod(new_from_service)
def set_data_listener(self, callback):
self._callback = callback
def _recv(self, address, data):
if self._callback:
self._callback(address, data)
class UnicastStreamWriter(object):
def __init__(self, stream, service):
# set up the writer
self._service = service
if not service.get_address():
raise ValueError("service must have a valid address.")
self._address = self._service.get_address()
self._port = self._service.get_port()
self._xmlrpc_addr = "http://%s:%d" % (self._address, self._port)
self._writer = network.GlibServerProxy(self._xmlrpc_addr)
def write(self, xmlrpc_data):
"""Write some data to the default endpoint of this pipe on the remote server."""
try:
self._writer.message(None, None, xmlrpc_data)
return True
except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
traceback.print_exc()
return False
def custom_request(self, method_name, request_cb, user_data, *args):
"""Call a custom XML-RPC method on the remote server."""
try:
method = getattr(self._writer, method_name)
method(request_cb, user_data, *args)
return True
except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
traceback.print_exc()
return False
class UnicastStream(Stream):
def __init__(self, service, start_reader=True):
"""Initializes the stream. If the 'start_reader' argument is True,
the stream will initialize and start a new stream reader, if it
is False, no reader will be created and the caller must call the
start_reader() method to start the stream reader and be able to
receive any data from the stream."""
Stream.__init__(self, service)
if start_reader:
self.start_reader()
def start_reader(self):
"""Start the stream's reader, which for UnicastStream objects is
and XMLRPC server. If there's a port conflict with some other
service, the reader will try to find another port to use instead.
Returns the port number used for the reader."""
# Set up the reader
self._reader = network.GlibXMLRPCServer(("", self._reader_port))
self._reader.register_function(self._message, "message")
def _message(self, message):
"""Called by the XMLRPC server when network data arrives."""
address = network.get_authinfo()
self._recv(address, message)
return True
def register_reader_handler(self, handler, name):
"""Register a custom message handler with the reader. This call
adds a custom XMLRPC method call with the name 'name' to the reader's
XMLRPC server, which then calls the 'handler' argument back when
a method call for it arrives over the network."""
if name == "message":
raise ValueError("Handler name 'message' is a reserved handler.")
self._reader.register_function(handler, name)
def new_writer(self, service):
"""Return a new stream writer object."""
return UnicastStreamWriter(self, service)
class MulticastStream(Stream):
def __init__(self, service):
Stream.__init__(self, service)
self._service = service
self._internal_start_reader()
def start_reader(self):
return self._reader_port
def _internal_start_reader(self):
logging.debug('Start multicast stream, address %s, port %d' % (self._address, self._reader_port))
if not self._service.get_address():
raise ValueError("service must have a valid address.")
self._pipe = MostlyReliablePipe('', self._address, self._reader_port,
self._recv_data_cb)
self._pipe.start()
def write(self, data):
self._pipe.send(data)
def _recv_data_cb(self, address, data, user_data=None):
self._recv(address[0], data)
def new_writer(self, service=None):
return self

View File

View File

@ -1,579 +0,0 @@
# Copyright (C) 2006, Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
# pylint: disable-msg = W0221
import socket
import os
import threading
import traceback
import xmlrpclib
import sys
import httplib
import urllib
import fcntl
import gobject
import SimpleXMLRPCServer
import SimpleHTTPServer
import SocketServer
__authinfos = {}
def _add_authinfo(authinfo):
__authinfos[threading.currentThread()] = authinfo
def get_authinfo():
return __authinfos.get(threading.currentThread())
def _del_authinfo():
del __authinfos[threading.currentThread()]
class GlibTCPServer(SocketServer.TCPServer):
"""GlibTCPServer
Integrate socket accept into glib mainloop.
"""
allow_reuse_address = True
request_queue_size = 20
def __init__(self, server_address, RequestHandlerClass):
SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)
self.socket.setblocking(0) # Set nonblocking
# Watch the listener socket for data
gobject.io_add_watch(self.socket, gobject.IO_IN, self._handle_accept)
def _handle_accept(self, source, condition):
"""Process incoming data on the server's socket by doing an accept()
via handle_request()."""
if not (condition & gobject.IO_IN):
return True
self.handle_request()
return True
class ChunkedGlibHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
"""RequestHandler class that integrates with Glib mainloop. It writes
the specified file to the client in chunks, returning control to the
mainloop between chunks.
"""
CHUNK_SIZE = 4096
def __init__(self, request, client_address, server):
self._file = None
self._srcid = 0
SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, request, client_address, server)
def log_request(self, code='-', size='-'):
pass
def do_GET(self):
"""Serve a GET request."""
self._file = self.send_head()
if self._file:
self._srcid = gobject.io_add_watch(self.wfile, gobject.IO_OUT | gobject.IO_ERR, self._send_next_chunk)
else:
self._file.close()
self._cleanup()
def _send_next_chunk(self, source, condition):
if condition & gobject.IO_ERR:
self._cleanup()
return False
if not (condition & gobject.IO_OUT):
self._cleanup()
return False
data = self._file.read(self.CHUNK_SIZE)
count = os.write(self.wfile.fileno(), data)
if count != len(data) or len(data) != self.CHUNK_SIZE:
self._cleanup()
return False
return True
def _cleanup(self):
if self._file:
self._file.close()
if self._srcid > 0:
gobject.source_remove(self._srcid)
self._srcid = 0
if not self.wfile.closed:
self.wfile.flush()
self.wfile.close()
self.rfile.close()
def finish(self):
"""Close the sockets when we're done, not before"""
pass
def send_head(self):
"""Common code for GET and HEAD commands.
This sends the response code and MIME headers.
Return value is either a file object (which has to be copied
to the outputfile by the caller unless the command was HEAD,
and must be closed by the caller under all circumstances), or
None, in which case the caller has nothing further to do.
** [dcbw] modified to send Content-disposition filename too
"""
path = self.translate_path(self.path)
f = None
if os.path.isdir(path):
for index in "index.html", "index.htm":
index = os.path.join(path, index)
if os.path.exists(index):
path = index
break
else:
return self.list_directory(path)
ctype = self.guess_type(path)
try:
# Always read in binary mode. Opening files in text mode may cause
# newline translations, making the actual size of the content
# transmitted *less* than the content-length!
f = open(path, 'rb')
except IOError:
self.send_error(404, "File not found")
return None
self.send_response(200)
self.send_header("Content-type", ctype)
self.send_header("Content-Length", str(os.fstat(f.fileno())[6]))
self.send_header("Content-Disposition", 'attachment; filename="%s"' % os.path.basename(path))
self.end_headers()
return f
class GlibURLDownloader(gobject.GObject):
"""Grabs a URL in chunks, returning to the mainloop after each chunk"""
__gsignals__ = {
'finished': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
'error': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT]))
}
CHUNK_SIZE = 4096
def __init__(self, url, destdir=None):
self._url = url
if not destdir:
destdir = "/tmp"
self._destdir = destdir
self._srcid = 0
self._fname = None
self._outf = None
gobject.GObject.__init__(self)
def start(self):
self._info = urllib.urlopen(self._url)
self._suggested_fname = self._get_filename_from_headers(self._info.headers)
import tempfile
garbage, path = urllib.splittype(self._url)
garbage, path = urllib.splithost(path or "")
path, garbage = urllib.splitquery(path or "")
path, garbage = urllib.splitattr(path or "")
suffix = os.path.splitext(path)[1]
(self._outf, self._fname) = tempfile.mkstemp(suffix=suffix, dir=self._destdir)
fcntl.fcntl(self._info.fp.fileno(), fcntl.F_SETFD, os.O_NDELAY)
self._srcid = gobject.io_add_watch(self._info.fp.fileno(),
gobject.IO_IN | gobject.IO_ERR,
self._read_next_chunk)
def _get_filename_from_headers(self, headers):
if not headers.has_key("Content-Disposition"):
return None
ftag = "filename="
data = headers["Content-Disposition"]
fidx = data.find(ftag)
if fidx < 0:
return None
fname = data[fidx+len(ftag):]
if fname[0] == '"' or fname[0] == "'":
fname = fname[1:]
if fname[len(fname)-1] == '"' or fname[len(fname)-1] == "'":
fname = fname[:len(fname)-1]
return fname
def _read_next_chunk(self, source, condition):
if condition & gobject.IO_ERR:
self.cleanup()
os.remove(self._fname)
self.emit("error", "Error downloading file.")
return False
elif not (condition & gobject.IO_IN):
# shouldn't get here, but...
return True
try:
data = self._info.fp.read(self.CHUNK_SIZE)
count = os.write(self._outf, data)
if len(data) < self.CHUNK_SIZE:
self.cleanup()
self.emit("finished", self._fname, self._suggested_fname)
return False
if count < len(data):
self.cleanup()
self.emit("error", "Error writing to download file.")
return False
except Exception, err:
self.cleanup()
self.emit("error", "Error downloading file: %s" % err)
return False
return True
def cleanup(self):
if self._srcid > 0:
gobject.source_remove(self._srcid)
self._srcid = 0
del self._info
self._info = None
os.close(self._outf)
self._outf = None
class GlibXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
""" GlibXMLRPCRequestHandler
The stock SimpleXMLRPCRequestHandler and server don't allow any way to pass
the client's address and/or SSL certificate into the function that actually
_processes_ the request. So we have to store it in a thread-indexed dict.
"""
def do_POST(self):
_add_authinfo(self.client_address)
try:
SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
except socket.timeout:
pass
except socket.error, e:
print "Error (%s): socket error - '%s'" % (self.client_address, e)
except:
print "Error while processing POST:"
traceback.print_exc()
_del_authinfo()
class GlibXMLRPCServer(GlibTCPServer, SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
"""GlibXMLRPCServer
Use nonblocking sockets and handle the accept via glib rather than
blocking on accept().
"""
def __init__(self, addr, requestHandler=GlibXMLRPCRequestHandler,
logRequests=0, allow_none=False):
self.logRequests = logRequests
if sys.version_info[:3] >= (2, 5, 0):
SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding="utf-8")
else:
SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
GlibTCPServer.__init__(self, addr, requestHandler)
def _marshaled_dispatch(self, data, dispatch_method = None):
"""Dispatches an XML-RPC method from marshalled (XML) data.
XML-RPC methods are dispatched from the marshalled (XML) data
using the _dispatch method and the result is returned as
marshalled data. For backwards compatibility, a dispatch
function can be provided as an argument (see comment in
SimpleXMLRPCRequestHandler.do_POST) but overriding the
existing method through subclassing is the prefered means
of changing method dispatch behavior.
"""
params, method = xmlrpclib.loads(data)
# generate response
try:
if dispatch_method is not None:
response = dispatch_method(method, params)
else:
response = self._dispatch(method, params)
# wrap response in a singleton tuple
response = (response,)
response = xmlrpclib.dumps(response, methodresponse=1)
except xmlrpclib.Fault, fault:
response = xmlrpclib.dumps(fault)
except:
print "Exception while processing request:"
traceback.print_exc()
# report exception back to server
response = xmlrpclib.dumps(
xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
)
return response
class GlibHTTP(httplib.HTTP):
"""Subclass HTTP so we can return it's connection class' socket."""
def connect(self, host=None, port=None):
httplib.HTTP.connect(self, host, port)
self._conn.sock.setblocking(0)
class GlibXMLRPCTransport(xmlrpclib.Transport):
"""Integrate the request with the glib mainloop rather than blocking."""
##
# Connect to server.
#
# @param host Target host.
# @return A connection handle.
def __init__(self, use_datetime=0):
if sys.version_info[:3] >= (2, 5, 0):
xmlrpclib.Transport.__init__(self, use_datetime)
def make_connection(self, host):
"""Use our own connection object so we can get its socket."""
# create a HTTP connection object from a host descriptor
host, extra_headers, x509 = self.get_host_info(host)
return GlibHTTP(host)
##
# Send a complete request, and parse the response.
#
# @param host Target host.
# @param handler Target PRC handler.
# @param request_body XML-RPC request body.
# @param verbose Debugging flag.
# @return Parsed response.
def start_request(self, host, handler, request_body, verbose=0, reply_handler=None, error_handler=None, user_data=None):
"""Do the first half of the request by sending data to the remote
server. The bottom half bits get run when the remote server's response
actually comes back."""
# issue XML-RPC request
h = self.make_connection(host)
if verbose:
h.set_debuglevel(1)
self.send_request(h, handler, request_body)
self.send_host(h, host)
self.send_user_agent(h)
self.send_content(h, request_body)
# Schedule a GIOWatch so we don't block waiting for the response
gobject.io_add_watch(h._conn.sock, gobject.IO_IN, self._finish_request,
h, host, handler, verbose, reply_handler, error_handler, user_data)
def _finish_request(self, source, condition, h, host, handler, verbose, reply_handler=None, error_handler=None, user_data=None):
"""Parse and return response when the remote server actually returns it."""
if not (condition & gobject.IO_IN):
return True
try:
errcode, errmsg, headers = h.getreply()
except socket.error, err:
if err[0] != 104:
raise socket.error(err)
else:
if error_handler:
gobject.idle_add(error_handler, err, user_data)
return False
if errcode != 200:
raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers)
self.verbose = verbose
response = self._parse_response(h.getfile(), h._conn.sock)
if reply_handler:
# Coerce to a list so we can append user data
response = response[0]
if not isinstance(response, list):
response = [response]
response.append(user_data)
gobject.idle_add(reply_handler, *response)
return False
class _Method:
"""Right, so python people thought it would be funny to make this
class private to xmlrpclib.py..."""
# some magic to bind an XML-RPC method to an RPC server.
# supports "nested" methods (e.g. examples.getStateName)
def __init__(self, send, name):
self.__send = send
self.__name = name
def __getattr__(self, name):
return _Method(self.__send, "%s.%s" % (self.__name, name))
def __call__(self, *args, **kwargs):
return self.__send(self.__name, *args, **kwargs)
class GlibServerProxy(xmlrpclib.ServerProxy):
"""Subclass xmlrpclib.ServerProxy so we can run the XML-RPC request
in two parts, integrated with the glib mainloop, such that we don't
block anywhere.
Using this object is somewhat special; it requires more arguments to each
XML-RPC request call than the normal xmlrpclib.ServerProxy object:
client = GlibServerProxy("http://127.0.0.1:8888")
user_data = "bar"
xmlrpc_arg1 = "test"
xmlrpc_arg2 = "foo"
client.test(xmlrpc_test_cb, user_data, xmlrpc_arg1, xmlrpc_arg2)
Here, 'xmlrpc_test_cb' is the callback function, which has the following
signature:
def xmlrpc_test_cb(result_status, response, user_data=None):
...
"""
def __init__(self, uri, encoding=None, verbose=0, allow_none=0):
self._transport = GlibXMLRPCTransport()
self._encoding = encoding
self._verbose = verbose
self._allow_none = allow_none
xmlrpclib.ServerProxy.__init__(self, uri, self._transport, encoding, verbose, allow_none)
# get the url
import urllib
urltype, uri = urllib.splittype(uri)
if urltype not in ("http", "https"):
raise IOError, "unsupported XML-RPC protocol"
self._host, self._handler = urllib.splithost(uri)
if not self._handler:
self._handler = "/RPC2"
def __request(self, methodname, *args, **kwargs):
"""Call the method on the remote server. We just start the request here
and the transport itself takes care of scheduling the response callback
when the remote server returns the response. We don't want to block anywhere."""
request = xmlrpclib.dumps(args, methodname, encoding=self._encoding,
allow_none=self._allow_none)
reply_hdl = kwargs.get("reply_handler")
err_hdl = kwargs.get("error_handler")
udata = kwargs.get("user_data")
try:
response = self._transport.start_request(
self._host,
self._handler,
request,
verbose=self._verbose,
reply_handler=reply_hdl,
error_handler=err_hdl,
user_data=udata
)
except socket.error, exc:
if err_hdl:
gobject.idle_add(err_hdl, exc, udata)
def __getattr__(self, name):
# magic method dispatcher
return _Method(self.__request, name)
class GroupServer(object):
_MAX_MSG_SIZE = 500
def __init__(self, address, port, data_cb):
self._address = address
self._port = port
self._data_cb = data_cb
self._setup_listener()
def _setup_listener(self):
# Listener socket
self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Set some options to make it multicast-friendly
self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
def start(self):
# Set some more multicast options
self._listen_sock.bind(('', self._port))
self._listen_sock.settimeout(2)
intf = socket.gethostbyname(socket.gethostname())
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(self._address) + socket.inet_aton('0.0.0.0'))
# Watch the listener socket for data
gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
def _handle_incoming_data(self, source, condition):
if not (condition & gobject.IO_IN):
return True
msg = {}
msg['data'], (msg['addr'], msg['port']) = source.recvfrom(self._MAX_MSG_SIZE)
if self._data_cb:
self._data_cb(msg)
return True
class GroupClient(object):
_MAX_MSG_SIZE = 500
def __init__(self, address, port):
self._address = address
self._port = port
self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Make the socket multicast-aware, and set TTL.
self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
def send_msg(self, data):
self._send_sock.sendto(data, (self._address, self._port))
class Test(object):
def test(self, arg1, arg2):
print "Request got %s, %s" % (arg1, arg2)
return "success", "bork"
def xmlrpc_success_cb(response, resp2, loop):
print "Response was %s %s" % (response, resp2)
loop.quit()
def xmlrpc_error_cb(err, loop):
print "Error: %s" % err
loop.quit()
def xmlrpc_test(loop):
client = GlibServerProxy("http://127.0.0.1:8888")
client.test("bar", "baz",
reply_handler=xmlrpc_success_cb,
error_handler=xmlrpc_error_cb,
user_data=loop)
def main():
loop = gobject.MainLoop()
server = GlibXMLRPCServer(("", 8888))
inst = Test()
server.register_instance(inst)
gobject.idle_add(xmlrpc_test, loop)
try:
loop.run()
except KeyboardInterrupt:
print 'Ctrl+C pressed, exiting...'
print "Done."
if __name__ == "__main__":
main()

View File

@ -1,136 +0,0 @@
#!/usr/bin/env python
# Copyright (C) 2006, Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import unittest
from sugar.datastore import datastore
from sugar import util
import dbus
class NotFoundError(dbus.DBusException): pass
_ds = datastore.get_instance()
class DataStoreTestCase(unittest.TestCase):
_TEST_DATA = "adsfkjadsfadskjasdkjf"
_TEST_PROPS = {'foo': 1, 'bar': 'baz'}
def _create_test_object(self, activity_id=None):
obj = _ds.create(self._TEST_DATA, self._TEST_PROPS, activity_id=activity_id)
self.assert_(obj)
return obj
def testObjectCreate(self):
obj = self._create_test_object()
self.assert_(obj.uid())
_ds.delete(obj)
def testObjectCreateWithActivityId(self):
# Try known good create
act_id = util.unique_id('afdkjakjddasf')
obj = self._create_test_object(act_id)
self.assert_(obj.uid())
_ds.delete(obj)
def testObjectCreateWithBadActivityId(self):
# try malformed activity id
try:
uid = self._create_test_object("adfadf")
except ValueError:
pass
else:
self.fail("Expected ValueError")
def testObjectGetActivityObject(self):
# create a new object
act_id = util.unique_id('afdkjakjddasf')
obj = self._create_test_object(act_id)
self.assert_(obj.uid())
obj2 = _ds.get(activity_id=act_id)
self.assert_(obj2)
_ds.delete(obj)
def testObjectGet(self):
# create a new object
obj = self._create_test_object()
self.assert_(obj.uid())
obj2 = _ds.get(obj.uid())
self.assert_(obj2)
_ds.delete(obj)
def testObjectDelete(self):
obj = self._create_test_object()
uid = obj.uid()
_ds.delete(obj)
try:
_ds.get(uid)
except dbus.DBusException, e:
if str(e).find("NotFoundError:") < 0:
self.fail("Expected a NotFoundError")
else:
self.fail("Expected a NotFoundError.")
def testObjectFind(self):
obj = self._create_test_object()
found = _ds.find(self._TEST_PROPS)
self.assert_(obj in found)
_ds.delete(obj)
def testObjectGetData(self):
obj = self._create_test_object()
data = obj.get_data()
self.assert_(data == self._TEST_DATA)
_ds.delete(obj)
_OTHER_DATA = "532532532532532;lkjkjkjfsakjfakjfdsakj"
def testObjectSetData(self):
obj = self._create_test_object()
data = obj.get_data()
self.assert_(data == self._TEST_DATA)
obj.set_data(self._OTHER_DATA)
data = obj.get_data()
self.assert_(data == self._OTHER_DATA)
_ds.delete(obj)
def testObjectGetProperties(self):
obj = self._create_test_object()
props = obj.get_properties()
for (key, value) in props.items():
if key == 'uid':
continue
self.assert_(key in self._TEST_PROPS)
self.assert_(str(self._TEST_PROPS[key]) == str(value))
for (key, value) in self._TEST_PROPS.items():
self.assert_(key in props)
self.assert_(str(props[key]) == str(value))
_ds.delete(obj)
def main():
dsTestSuite = unittest.TestSuite()
dsTestSuite.addTest(DataStoreTestCase('testObjectCreate'))
dsTestSuite.addTest(DataStoreTestCase('testObjectCreateWithActivityId'))
dsTestSuite.addTest(DataStoreTestCase('testObjectCreateWithBadActivityId'))
dsTestSuite.addTest(DataStoreTestCase('testObjectGet'))
dsTestSuite.addTest(DataStoreTestCase('testObjectGetActivityObject'))
dsTestSuite.addTest(DataStoreTestCase('testObjectDelete'))
dsTestSuite.addTest(DataStoreTestCase('testObjectFind'))
dsTestSuite.addTest(DataStoreTestCase('testObjectGetData'))
dsTestSuite.addTest(DataStoreTestCase('testObjectSetData'))
dsTestSuite.addTest(DataStoreTestCase('testObjectGetProperties'))
unittest.TextTestRunner(verbosity=2).run(dsTestSuite)
if __name__ == "__main__":
main()

View File

@ -1,50 +0,0 @@
#!/usr/bin/env python
# Copyright (C) 2006, One Laptop Per Child
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from sugar.datastore import datastore
from sugar.datastore.datastore import Text
# Write a text object
metadata = { 'date' : 1000900000,
'title' : 'Thai history',
'preview' : 'The subject of thai history...',
'icon-color' : '#C2B00C,#785C78',
}
text = Text(metadata)
f = open("/tmp/hello.txt", 'w')
try:
f.write('The subject of thai history blah blah blah, blah blah blah and blah.')
finally:
f.close()
text.set_file_path(f.name)
handle = datastore.write(text)
# Read back that object
thing = datastore.read(handle)
metadata = thing.get_metadata()
print metadata
file_path = thing.get_file_path()
f = open(file_path)
try:
print f.read()
finally:
f.close()
# Retrieve all the objects
objects = datastore.find('')
for obj in objects:
print obj.get_metadata()['title']

View File

@ -16,37 +16,15 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os
import sys
import pygtk
pygtk.require('2.0')
import gtk
import gobject
from sugar import objects
import sugar.browser
print 'MIME type for test.pdf (from extension):'
print objects.mime.get_from_file_name('test.pdf')
def _print_document():
#print browser.document
pass
print ''
def _quit(window):
sugar.browser.shutdown()
gtk.main_quit()
# Main window
window = gtk.Window()
window.connect("destroy", _quit)
sugar.browser.startup(os.path.expanduser('~/.sugar-browser-test'), 'test')
browser = sugar.browser.Browser()
window.add(browser)
browser.show()
browser.load_url('about:blank')
gobject.idle_add(_print_document)
window.show()
gtk.main()
if len(sys.argv) > 1:
print 'MIME type for file %s:' % sys.argv[1]
print objects.mime.get_for_file(sys.argv[1])