Author: remi
Date: 2009-03-16 22:36:52 +0100 (Mon, 16 Mar 2009)
New Revision: 4097

Added:
   
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/
   
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/SimpleGadget.py
   
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/SimpleGadgetConfiguration.py
   
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/__init__.py
Modified:
   
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/tux-gadget-clockradio.py
   
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/resources/gadget.xml
Log:
* added SimpleGadget class (portage of the java gadget toolkit)
* bumped to 0.0.4
  - Pyhton gadgets have now the same tool-kit as the java ones

Added: 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/SimpleGadget.py
===================================================================
--- 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/SimpleGadget.py
                            (rev 0)
+++ 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/SimpleGadget.py
    2009-03-16 21:36:52 UTC (rev 4097)
@@ -0,0 +1,304 @@
+#    Copyright (C) 2009 C2ME Sa
+#    Remi Jocaille <[email protected]>
+#    Distributed under the terms of the GNU General Public License
+#    http://www.gnu.org/copyleft/gpl.html
+#
+#    This module is a portage of the java package write by "Yoran Brault"
+#    "com.kysoh.tuxdroid.gadget.framework.gadget"
+
+import os
+import sys
+import traceback
+import random
+import platform
+
+ENVIRONEMENT_PREFIX = "tgp_"
+
+# 
------------------------------------------------------------------------------
+# This class is the base class helper for builder python gadgets.
+# 
------------------------------------------------------------------------------
+class SimpleGadget(object):
+    """This class is the base class helper for builder python gadgets.
+    """
+
+    # 
--------------------------------------------------------------------------
+    # Constructor of the class.
+    # 
--------------------------------------------------------------------------
+    def __init__(self):
+        """Constructor of the class.
+        """
+        self.__configuration = None
+        self.__command = None
+
+    # 
--------------------------------------------------------------------------
+    # Get the configuration object.
+    # 
--------------------------------------------------------------------------
+    def configuration(self):
+        """Get the configuration object.
+        @return: A SimpleGadgetConfiguration object.
+        """
+        return self.__configuration
+
+    # 
--------------------------------------------------------------------------
+    # Get the command of the gagdet.
+    # 
--------------------------------------------------------------------------
+    def getCommand(self):
+        """Get the command of the gagdet.
+        @return: A string.
+        """
+        return self.__command
+
+    # 
--------------------------------------------------------------------------
+    # Set the command of the gagdet.
+    # 
--------------------------------------------------------------------------
+    def setCommand(self, command):
+        """Set the command of the gagdet.
+        @param command: The command of the gagdet.
+        """
+        self.__command = command
+
+    # 
--------------------------------------------------------------------------
+    # Get if the platform is Windows or not.
+    # 
--------------------------------------------------------------------------
+    def isWindows(self):
+        """Get if the platform is Windows or not.
+        @return: A boolean.
+        """
+        platformName = platform.system().lower()
+        return (platformName == "microsoft") or (platformName == "windows")
+
+    # 
--------------------------------------------------------------------------
+    # Load the environement data to the gadget parameters.
+    # 
--------------------------------------------------------------------------
+    def __loadEnvironementData(self):
+        """Load the environement data to the gadget parameters.
+        """
+        if self.__configuration == None:
+            return
+        # Extract configuration object class names
+        baseConfClassName = "_SimpleGadgetConfiguration"
+        confClassName = str(self.__configuration.__class__)
+        confClassName = confClassName.split("'")[1].split(".")[1]
+        confClassName = "_" + confClassName
+        # Filtering the fields of the configuration object
+        confFields = dir(self.__configuration)
+        filteredFileds = []
+        for field in confFields:
+            if field.find(baseConfClassName) == 0:
+                filteredFileds.append([field[len(baseConfClassName):].lower(),
+                    field])
+            if field.find(confClassName) == 0:
+                filteredFileds.append([field[len(confClassName):].lower(),
+                    field])
+        # Fill the configuration parameters with the environement values
+        self.throwTrace("Loading environement")
+        for key in os.environ:
+            fKey = key.lower()
+            if fKey.find(ENVIRONEMENT_PREFIX) == 0:
+                environName = fKey[len(ENVIRONEMENT_PREFIX):]
+                for field in filteredFileds:
+                    if field[0][2:] == environName:
+                        # Get the value in the configuration object
+                        paramName = field[1]
+                        paramValue = getattr(self.__configuration, paramName)
+                        paramType = str(type(paramValue))
+                        paramType = paramType.split("'")[1]
+                        # Get the value in the os environ
+                        environValue = os.environ[key]
+                        self.throwTrace("   " + field[0][2:] + ":" + 
environValue);
+                        # Check parameters type
+                        if paramType == 'str':
+                            pass
+                        elif paramType == 'int':
+                            try:
+                                environValue = int(environValue)
+                            except:
+                                # Environ value type not match with the 
parameter
+                                self.throwError("", True)
+                                continue
+                        elif paramType == 'float':
+                            try:
+                                environValue = float(environValue)
+                            except:
+                                # Environ value type not match with the 
parameter
+                                self.throwError("", True)
+                                continue
+                        elif paramType == 'bool':
+                            if environValue == "true":
+                                environValue = "True"
+                            else:
+                                environValue = "False"
+                        else:
+                            # Unknow parameter type
+                            self.throwError("Unknow parameter type (%s)" % 
paramType)
+                            continue
+                        # Set the environment value to the parameter
+                        setattr(self.__configuration, paramName, environValue)
+
+    # 
--------------------------------------------------------------------------
+    # Starting point of the gadget.
+    # 
--------------------------------------------------------------------------
+    def boot(self, arguments, configuration):
+        """Starting point of the gadget.
+        @param arguments:
+        """
+        try:
+            if len(arguments) > 0:
+                self.__command = arguments[0]
+                self.__configuration = configuration
+                self.__loadEnvironementData()
+                self.start()
+        except:
+            self.throwError("Error on gadget boot", True)
+
+    # 
--------------------------------------------------------------------------
+    # Start method of the gadget. Must be overrided.
+    # 
--------------------------------------------------------------------------
+    def start(self):
+        """Start method of the gadget. (Must be overrided)
+        """
+        pass
+
+    # 
--------------------------------------------------------------------------
+    # Get the full path of a file located in the "state" directory of a 
deployed
+    # gadget.
+    # 
--------------------------------------------------------------------------
+    def __getStateFile(self, fileName):
+        """Get the full path of a file located in the "state" directory of a
+        deployed gadget.
+        @param fileName: Base file name.
+        @return: A full file path.
+        """
+        path = "states"
+        if not os.path.isdir(path):
+            try:
+                os.makedirs(path)
+            except:
+                return None
+        return os.path.join(path, fileName)
+
+    # 
--------------------------------------------------------------------------
+    # Read a serialized object from a file.
+    # 
--------------------------------------------------------------------------
+    def readState(self, fileName):
+        """Read a serialized object from a file.
+        @param fileName: File name of the serialized object.
+        @return: An object or None if fail.
+        """
+        sessionFile = self.__getStateFile(fileName)
+        if sessionFile == None:
+            return None
+        if not os.path.isfile(sessionFile):
+            return None
+        try:
+            f = open(sessionFile, "r")
+            state = eval(f.read())
+            f.close()
+        except:
+            return None
+        return state
+
+    # 
--------------------------------------------------------------------------
+    # Write a file with a serialized object.
+    # 
--------------------------------------------------------------------------
+    def writeState(self, myObject, fileName):
+        """Write a file with a serialized object.
+        @param myObject: Object to serialize.
+        @param fileName: File name of the serialized object.
+        """
+        sessionFile = self.__getStateFile(fileName)
+        try:
+            f = open(sessionFile, "w")
+            f.write(str(myObject))
+            f.close()
+        except:
+            pass
+
+    # 
--------------------------------------------------------------------------
+    # Write a pid file.
+    # 
--------------------------------------------------------------------------
+    def writePid(self, pid):
+        """Write a pid file.
+        @param pid: Process id.
+        """
+        fileName = str(random.random()).replace('.', '') + ".pid"
+        sessionFile = self.__getStateFile(fileName)
+        try:
+            f = open(sessionFile, "w")
+            f.write(str(pid))
+            f.close()
+        except:
+            pass
+
+    # 
--------------------------------------------------------------------------
+    # Throw a generic notification to the framework.
+    # 
--------------------------------------------------------------------------
+    def throwNotification(self, messageId, *args):
+        """Throw a generic notification to the framework.
+        @param messageId: Message Id.
+        @param args: List of objects.
+        """
+        stringBuffer = messageId
+        for arg in args:
+            stringBuffer += " '"
+            stringBuffer += str(arg).replace("'", "\\'")
+            stringBuffer += "'"
+        sys.stdout.write(stringBuffer + "\n")
+        sys.stdout.flush()
+
+    # 
--------------------------------------------------------------------------
+    # Throw a message to the framework.
+    # 
--------------------------------------------------------------------------
+    def throwMessage(self, content, *args):
+        """Throw a message to the framework.
+        @param content: Content of the message.
+        @param args: Arguments for the message.
+        """
+        tmp = [content,]
+        for arg in args:
+            tmp.append(arg)
+        self.throwNotification("message", *tmp)
+
+    # 
--------------------------------------------------------------------------
+    # Throw a trace message to the framework.
+    # 
--------------------------------------------------------------------------
+    def throwTrace(self, message):
+        """Throw a trace message to the framework.
+        @param message: Throwed message.
+        """
+        if not self.__configuration.isTraces():
+            return
+        self.throwNotification("trace", message)
+
+    # 
--------------------------------------------------------------------------
+    # Throw an error message to the framework.
+    # 
--------------------------------------------------------------------------
+    def throwError(self, message, force = False):
+        """Throw an error message to the framework.
+        @param message: Thowed message if the gadget don't want to be traced.
+            - if the gadget is traced, the traceback will be sent instead of 
the
+            message.
+        @param force: For to send the traceback. Default False.
+        """
+        if not force:
+            if self.__configuration.isTraces():
+                message = self.__formatException()
+        else:
+            message = self.__formatException()
+        message = message.split("\n")
+        self.throwNotification("error", *message)
+
+    # 
--------------------------------------------------------------------------
+    # Get the formated traceback of the last exception.
+    # 
--------------------------------------------------------------------------
+    def __formatException(self):
+        """Get the formated traceback of the last exception.
+        @return: A string.
+        """
+        fList = traceback.format_exception(sys.exc_info()[0],
+                    sys.exc_info()[1],
+                    sys.exc_info()[2])
+        result = ""
+        for line in fList:
+            result += line
+        return result


Property changes on: 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/SimpleGadget.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/SimpleGadgetConfiguration.py
===================================================================
--- 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/SimpleGadgetConfiguration.py
                               (rev 0)
+++ 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/SimpleGadgetConfiguration.py
       2009-03-16 21:36:52 UTC (rev 4097)
@@ -0,0 +1,116 @@
+#    Copyright (C) 2009 C2ME Sa
+#    Remi Jocaille <[email protected]>
+#    Distributed under the terms of the GNU General Public License
+#    http://www.gnu.org/copyleft/gpl.html
+#
+#    This module is a portage of the java package write by "Yoran Brault"
+#    "com.kysoh.tuxdroid.gadget.framework.gadget"
+
+# 
------------------------------------------------------------------------------
+# Class of the default gadget configuration.
+# 
------------------------------------------------------------------------------
+class SimpleGadgetConfiguration(object):
+    """Class of the default gadget configuration.
+    """
+
+    # 
--------------------------------------------------------------------------
+    # Constructor of the class.
+    # 
--------------------------------------------------------------------------
+    def __init__(self):
+        """Constructor of the class.
+        """
+        self.__traces = False
+        self.__pitch = 100
+        self.__language = "en"
+        self.__country = "US"
+        self.__locutor = "Ryan"
+
+    # 
--------------------------------------------------------------------------
+    # Get the pitch value.
+    # 
--------------------------------------------------------------------------
+    def getPitch(self):
+        """Get the pitch value.
+        @return: An integer.
+        """
+        return self.__pitch
+
+    # 
--------------------------------------------------------------------------
+    # Set the pitch value.
+    # 
--------------------------------------------------------------------------
+    def setPitch(self, pitch):
+        """Set the pitch value.
+        @param pitch: The pitch.
+        """
+        self.__pitch = pitch
+
+    # 
--------------------------------------------------------------------------
+    # Get the language.
+    # 
--------------------------------------------------------------------------
+    def getLanguage(self):
+        """Get the language.
+        @return: A string.
+        """
+        return self.__language
+
+    # 
--------------------------------------------------------------------------
+    # Set the language.
+    # 
--------------------------------------------------------------------------
+    def setLanguage(self, language):
+        """Set the language.
+        @param language: The language.
+        """
+        self.__language = language
+
+    # 
--------------------------------------------------------------------------
+    # Get the country.
+    # 
--------------------------------------------------------------------------
+    def getCountry(self):
+        """Get the country.
+        @return: A string.
+        """
+        return self.__country
+
+    # 
--------------------------------------------------------------------------
+    # Set the country.
+    # 
--------------------------------------------------------------------------
+    def setCountry(self, country):
+        """Set the country.
+        @param country: The country.
+        """
+        self.__country = country
+
+    # 
--------------------------------------------------------------------------
+    # Get the locutor.
+    # 
--------------------------------------------------------------------------
+    def getLocutor(self):
+        """Get the locutor.
+        @return: A string.
+        """
+        return self.__locutor
+
+    # 
--------------------------------------------------------------------------
+    # Set the locutor.
+    # 
--------------------------------------------------------------------------
+    def setLocutor(self, locutor):
+        """Set the locutor.
+        @param locutor: The locutor.
+        """
+        self.__locutor = locutor
+
+    # 
--------------------------------------------------------------------------
+    # Get if the gadget is traced or not.
+    # 
--------------------------------------------------------------------------
+    def isTraces(self):
+        """Get if the gadget is traced or not.
+        @return: A boolean.
+        """
+        return self.__traces
+
+    # 
--------------------------------------------------------------------------
+    # Set if the gadget is traced or not.
+    # 
--------------------------------------------------------------------------
+    def setTraces(self, traces):
+        """Set if the gadget is traced or not.
+        @param traces: Is traced or not.
+        """
+        self.__traces = traces


Property changes on: 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/SimpleGadgetConfiguration.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/__init__.py
===================================================================


Property changes on: 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/SimpleGadget/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/tux-gadget-clockradio.py
===================================================================
--- 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/tux-gadget-clockradio.py
        2009-03-16 15:36:14 UTC (rev 4096)
+++ 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/executables/tux-gadget-clockradio.py
        2009-03-16 21:36:52 UTC (rev 4097)
@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 
 # -----------------------------------------------------------------------------
-#Gadget à placer dans mes alerts pour que Tux vous réveiile avec une webradio
+# Gadget à placer dans mes alerts pour que Tux vous réveille avec une webradio
 #
 # 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
@@ -36,6 +36,12 @@
 2009/03/12 - version 0.0.3:
     - Add test for playing mms:
 
+2009/03/16 - version 0.0.4:
+    - Add a wrapper to mplayer
+    - Add compatibility with Windows
+    - Add SimpleGadget module
+    - Add a pid file for mplayer sub-process
+
 TODO LIST
 =========
 - Add more webradio
@@ -45,61 +51,73 @@
 
 __author__  = "Eric Lescaudron AKA Gwadavel"
 __appname__ = "tux clock radio"
-__version__ = "0.0.3"
-__date__    = "2009/03/12"
+__version__ = "0.0.4"
+__date__    = "2009/03/16"
 __license__ = "GPL"
 
 import os
 import time
-import random
 
+from SimpleGadget.SimpleGadgetConfiguration import SimpleGadgetConfiguration
+from SimpleGadget.SimpleGadget import SimpleGadget
 from mplayer.Mplayer import Mplayer
 
-DEBUG = False
+# Web radios dictionary
+WEBRADIO = {
+    "France-Inter" : 
"http://viphttp.yacast.net/V4/radiofrance/franceinter_hd.m3u";,
+    "RMC-Info" : "http://cache.yacast.fr/V4/rmc/rmc.m3u";,
+    "France-Info" : 
"http://viphttp.yacast.net/V4/radiofrance/franceinfo_bd.m3u";,
+    "France-Culture" : 
"http://viphttp.yacast.net/V4/radiofrance/franceculture_hd.m3u";,
+    "Le-Mouv" : "http://viphttp.yacast.net/V4/radiofrance/lemouv_hd.m3u";,
+    "France-Musique" : 
"http://viphttp.yacast.net/V4/radiofrance/francemusique_hd.m3u";,
+    "France-Bleu-Ile-de-France" : 
"http://viphttp.yacast.net/V4/radiofrance/francebleu_idf_hd.m3u";,
+    "BBC2" : "http://www.bbc.co.uk/radio2/realmedia/fmg2.ram";,
+    "RFM" : "mms://viplagardere.yacast.net/encoderrfm",
+    "Click'And'rock" : "mms://viplagardere.yacast.net/encoderrfm"
+}
 
-# 
==============================================================================
-# Class to retrieve the py file path.
-# 
==============================================================================
-class localFilePath(object):
-    """Class to retrieve the local file path.
-    """
-    def getPath(self):
-        """Get the local file path.
-        """
-        mPath, mFile = os.path.split(__file__)
-        return mPath
+class Configuration(SimpleGadgetConfiguration):
 
-# Web radios dictionary
-WEBRADIO = 
{"France-Inter":"http://viphttp.yacast.net/V4/radiofrance/franceinter_hd.m3u";,
-            "RMC-Info":"http://cache.yacast.fr/V4/rmc/rmc.m3u";,
-            
"France-Info":"http://viphttp.yacast.net/V4/radiofrance/franceinfo_bd.m3u";,
-            
"France-Culture":"http://viphttp.yacast.net/V4/radiofrance/franceculture_hd.m3u";,
-            "Le-Mouv":"http://viphttp.yacast.net/V4/radiofrance/lemouv_hd.m3u";,
-            
"France-Musique":"http://viphttp.yacast.net/V4/radiofrance/francemusique_hd.m3u";,
-            
"France-Bleu-Ile-de-France":"http://viphttp.yacast.net/V4/radiofrance/francebleu_idf_hd.m3u";,
-            "BBC2":"http://www.bbc.co.uk/radio2/realmedia/fmg2.ram";,
-            "RFM":"mms://viplagardere.yacast.net/encoderrfm",
-            "Click'And'rock":"mms://viplagardere.yacast.net/encoderrfm"}
+    def __init__(self):
+        SimpleGadgetConfiguration.__init__(self)
+        self.__radio = "France-Inter"
 
-# Get the parameter "radio" of the gadget
-radioName = os.environ['tgp_radio']
-# Check if the web radio is referenced
-if not radioName in WEBRADIO.keys():
-    # If the radio is not referenced as radio name then get it as webradio url
-    radio = radioName
-else:
-    radio = WEBRADIO[radioName]
-# Create a mplayer wrapper object
-player = Mplayer()
-# Start mplayer
-player.start(radio, True)
-# Wait that the wrapper thread has been launched
-time.sleep(1.0)
-# Get the gadget working path
-workingPath = os.path.split(localFilePath().getPath())[0]
-# Create a pid file with a random name (random for multisession)
-# This pid file will be read by the framework at the gadget stop in order to
-# kill mplayer if it still started.
-pidFilename = str(random.random()).replace('.', '') + ".pid"
-pid = player.getPid()
-open(os.path.join(workingPath, pidFilename), "w").write(str(pid))
+    def getRadio(self):
+        return self.__radio
+
+    def setRadio(self, radio):
+        self.__radio = radio
+
+class WebRadioGadget(SimpleGadget):
+
+    def start(self):
+        if self.getCommand() == "check":
+            self.check()
+        else:
+            self.run()
+
+    def run(self):
+        self.__doExecute()
+
+    def check(self):
+        self.__doExecute()
+
+    def __doExecute(self):
+        myRadio = self.configuration().getRadio()
+        radioUrl = myRadio
+        if myRadio in WEBRADIO.keys():
+            radioUrl = WEBRADIO[myRadio]
+            self.throwMessage("Web radio \"{0}\"", myRadio)
+        # Create a mplayer wrapper object
+        player = Mplayer()
+        # Start mplayer
+        player.start(radioUrl, True)
+        # Wait that the wrapper thread has been launched
+        time.sleep(1.0)
+        # Create a pid file for mplayer.
+        self.writePid(player.getPid())
+
+if __name__ == "__main__":
+    import sys
+    gadget = WebRadioGadget()
+    gadget.boot(sys.argv[1:], Configuration())

Modified: 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/resources/gadget.xml
===================================================================
--- 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/resources/gadget.xml
        2009-03-16 15:36:14 UTC (rev 4096)
+++ 
software_suite_v2/software/gadgets/tuxdroid-gadget-clockradio/branches/0.0.3-windows-compatible/resources/gadget.xml
        2009-03-16 21:36:52 UTC (rev 4097)
@@ -5,9 +5,9 @@
        </interpreter>
        <description>
                <name>Clock Radio</name>
-               <description>Use tux as webradio or clock radio</description>
+               <description>Use tux as webradio</description>
                <author>Gwadavel</author>
-               <version>0.0.3</version>
+               <version>0.0.4</version>
                <iconFile>resources/clockradio.png</iconFile>
                <executionMode>command</executionMode>
                <uuid>8349ed52-572d-4c3f-a7b8-05c2a8aec2c6</uuid>


------------------------------------------------------------------------------
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
_______________________________________________
Tux-droid-svn mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tux-droid-svn

Reply via email to