From e69fb39342e8b6f4897ebab96dd7ee3ecb234e06 Mon Sep 17 00:00:00 2001 From: 0312birdzhang <0312birdzhang@gmail.com> Date: Fri, 7 Aug 2015 19:40:21 +0800 Subject: [PATCH] init --- .gitignore | 3 + harbour-python3ftp.desktop | 7 + harbour-python3ftp.png | Bin 0 -> 2965 bytes harbour-python3ftp.pro | 38 +++ qml/cover/CoverPage.qml | 41 +++ qml/harbour-python3ftp.qml | 41 +++ qml/pages/FirstPage.qml | 88 ++++++ qml/pages/simpleftp.py | 434 ++++++++++++++++++++++++++ rpm/harbour-python3ftp.changes.in | 15 + rpm/harbour-python3ftp.spec | 72 +++++ rpm/harbour-python3ftp.yaml | 46 +++ src/harbour-python3ftp.cpp | 48 +++ translations/harbour-python3ftp-de.ts | 41 +++ translations/harbour-python3ftp.ts | 11 + 14 files changed, 885 insertions(+) create mode 100644 .gitignore create mode 100644 harbour-python3ftp.desktop create mode 100644 harbour-python3ftp.png create mode 100644 harbour-python3ftp.pro create mode 100644 qml/cover/CoverPage.qml create mode 100644 qml/harbour-python3ftp.qml create mode 100644 qml/pages/FirstPage.qml create mode 100755 qml/pages/simpleftp.py create mode 100644 rpm/harbour-python3ftp.changes.in create mode 100644 rpm/harbour-python3ftp.spec create mode 100644 rpm/harbour-python3ftp.yaml create mode 100644 src/harbour-python3ftp.cpp create mode 100644 translations/harbour-python3ftp-de.ts create mode 100644 translations/harbour-python3ftp.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f0d180e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc +*.pyo +*.user* diff --git a/harbour-python3ftp.desktop b/harbour-python3ftp.desktop new file mode 100644 index 0000000..9939eae --- /dev/null +++ b/harbour-python3ftp.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Application +X-Nemo-Application-Type=silica-qt5 +Icon=harbour-python3ftp +Exec=harbour-python3ftp +Name=Python FTP + diff --git a/harbour-python3ftp.png b/harbour-python3ftp.png new file mode 100644 index 0000000000000000000000000000000000000000..4c883a0ec7f3c6c6c18fa9e376d98d9d2520c161 GIT binary patch literal 2965 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 LNkvXXu0mjfbPB7e literal 0 HcmV?d00001 diff --git a/harbour-python3ftp.pro b/harbour-python3ftp.pro new file mode 100644 index 0000000..36ea108 --- /dev/null +++ b/harbour-python3ftp.pro @@ -0,0 +1,38 @@ +# NOTICE: +# +# Application name defined in TARGET has a corresponding QML filename. +# If name defined in TARGET is changed, the following needs to be done +# to match new name: +# - corresponding QML filename must be changed +# - desktop icon filename must be changed +# - desktop filename must be changed +# - icon definition filename in desktop file must be changed +# - translation filenames have to be changed + +# The name of your application +TARGET = harbour-python3ftp + +CONFIG += sailfishapp + +SOURCES += src/harbour-python3ftp.cpp + +OTHER_FILES += qml/harbour-python3ftp.qml \ + qml/cover/CoverPage.qml \ + qml/pages/FirstPage.qml \ + rpm/harbour-python3ftp.changes.in \ + rpm/harbour-python3ftp.spec \ + rpm/harbour-python3ftp.yaml \ + translations/*.ts \ + qml/pages/simpleftp.py \ + harbour-python3ftp.desktop + +# to disable building translations every time, comment out the +# following CONFIG line +CONFIG += sailfishapp_i18n + +# German translation is enabled as an example. If you aren't +# planning to localize your app, remember to comment out the +# following TRANSLATIONS line. And also do not forget to +# modify the localized app name in the the .desktop file. +TRANSLATIONS += translations/harbour-python3ftp-de.ts + diff --git a/qml/cover/CoverPage.qml b/qml/cover/CoverPage.qml new file mode 100644 index 0000000..12ea71f --- /dev/null +++ b/qml/cover/CoverPage.qml @@ -0,0 +1,41 @@ +/* + Copyright (C) 2013 Jolla Ltd. + Contact: Thomas Perl + All rights reserved. + + You may use this file under the terms of BSD license as follows: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Jolla Ltd nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import QtQuick 2.0 +import Sailfish.Silica 1.0 + +CoverBackground { + CoverPlaceholder{ + icon.source:"/usr/share/icons/hicolor/86x86/apps/harbour-python3ftp.png" + text:"Ftp Client" + } +} + + diff --git a/qml/harbour-python3ftp.qml b/qml/harbour-python3ftp.qml new file mode 100644 index 0000000..bb031a4 --- /dev/null +++ b/qml/harbour-python3ftp.qml @@ -0,0 +1,41 @@ +/* + Copyright (C) 2013 Jolla Ltd. + Contact: Thomas Perl + All rights reserved. + + You may use this file under the terms of BSD license as follows: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Jolla Ltd nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import "pages" + +ApplicationWindow +{ + initialPage: Component { FirstPage { } } + cover: Qt.resolvedUrl("cover/CoverPage.qml") +} + + diff --git a/qml/pages/FirstPage.qml b/qml/pages/FirstPage.qml new file mode 100644 index 0000000..30ea8da --- /dev/null +++ b/qml/pages/FirstPage.qml @@ -0,0 +1,88 @@ +/* + Copyright (C) 2013 Jolla Ltd. + Contact: Thomas Perl + All rights reserved. + + You may use this file under the terms of BSD license as follows: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Jolla Ltd nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import io.thp.pyotherside 1.3 + +Page { + id: page + property string displaylog: "" + Python{ + id:ftppy + Component.onCompleted: { + addImportPath(Qt.resolvedUrl('./')); + ftppy.importModule('simpleftp',function () { + ftppy.startFtp(); + }); + + + } + + function startFtp(){ + ftppy.call('simpleftp.mymain',[],function(result){ + }); + } + + onReceived:{ + displaylog+=data.toString()+"
" + } + } + + SilicaFlickable { + id:view + anchors.fill: parent + contentHeight: header.height + desc.height + Theme.paddingLarge*2 + + PageHeader { + id:header + title: qsTr("Python FTP") + } + Label{ + id:desc + width: parent.width + wrapMode: Text.WordWrap + font.pixelSize: Theme.fontSizeMedium + truncationMode: TruncationMode.Fade + text: displaylog + color: view.highlighted ? Theme.highlightColor : Theme.primaryColor + anchors{ + top:header.bottom + //horizontalCenter: parent.horizontalCenter + left:parent.left + right:parent.right + margins: Theme.paddingLarge + } + } + + } +} + + diff --git a/qml/pages/simpleftp.py b/qml/pages/simpleftp.py new file mode 100755 index 0000000..d30c376 --- /dev/null +++ b/qml/pages/simpleftp.py @@ -0,0 +1,434 @@ +# modifyDate: 20120808 ~ 20120810 +# 原作者为:bones7456, http://li2z.cn/ +# 修改者为:decli@qq.com +# python3版本修改者 : 0312birdzhang@gmail.com +# v1.2,changeLog: +# +: 文件日期/时间/颜色显示、多线程支持、主页跳转 +# -: 解决不同浏览器下上传文件名乱码问题:仅IE,其它浏览器暂时没处理。 +# -: 一些路径显示的bug,主要是 cgi.escape() 转义问题 +# ?: notepad++ 下直接编译的server路径问题 + +""" + 简介:这是一个 python 写的轻量级的文件共享服务器(基于内置的SimpleHTTPServer模块), + 支持文件上传下载,只要你安装了python(建议版本2.6~2.7,不支持3.x), + 然后去到想要共享的目录下,执行: + python SimpleHTTPServerWithUpload.py 1234 + 其中1234为你指定的端口号,如不写,默认为 8080 + 然后访问 http://localhost:1234 即可,localhost 或者 1234 请酌情替换。 +""" + +"""Simple HTTP Server With Upload. + +This module builds on BaseHTTPServer by implementing the standard GET +and HEAD requests in a fairly straightforward manner. + +""" + +__version__ = "0.1" +__all__ = ["SimpleHTTPRequestHandler"] +__author__ = "bones7456" +__home_page__ = "" + +import os, sys, platform +import posixpath +import http.server +from socketserver import ThreadingMixIn +import threading +import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse +import cgi +import shutil +import mimetypes +import re +import time +import pyotherside + +try: + from io import StringIO +except ImportError: + from io import StringIO + +def get_ip_address(ifname): + import socket + import fcntl + import struct + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + return socket.inet_ntoa(fcntl.ioctl( + s.fileno(), + 0x8915, # SIOCGIFADDR + struct.pack(b'256s', ifname[:15]) + )[20:24]) + except: + return "You may not connected to wifi" + +class GetWanIp: + def getip(self): + try: + myip = self.visit("http://ip.taobao.com/service/getIpInfo.php?ip=myip") + except: + pyotherside("ip.taobao.com is Error") + try: + myip = self.visit("http://www.bliao.com/ip.phtml") + except: + print("bliao.com is Error") + try: + myip = self.visit("http://www.whereismyip.com/") + except: # 'NoneType' object has no attribute 'group' + print("whereismyip is Error") + myip = "127.0.0.1" + return myip + def visit(self,url): + #req = urllib2.Request(url) + #values = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537', + # 'Referer': 'http://ip.taobao.com/ipSearch.php', + # 'ip': 'myip' + # } + #data = urllib.urlencode(values) + opener = urllib.request.urlopen(url, None, 3) + if url == opener.geturl(): + str = opener.read() + return re.search('(\d+\.){3}\d+',str).group(0) + +def showTips(): + pyotherside.send("") + pyotherside.send('-------->>Starting------------ ') + pyotherside.send("") + # try: + # port = int(sys.argv[1]) + # except Exception as e: + # pyotherside.send('-------->> Warning: Port is not given, will use deafult port: 8080 ') + # pyotherside.send('-------->> if you want to use other port, please execute: ') + # pyotherside.send('-------->> python SimpleHTTPServerWithUpload.py port ') + # pyotherside.send("-------->> port is a integer and it's range: 1024 < port < 65535 ") + port = 9537 + + if not 1024 < port < 65535: port = 9898 + # serveraddr = ('', port) + pyotherside.send('-------->> Ftp Server started !') + pyotherside.send("") + pyotherside.send('-------->> Now, listening at port ' + str(port) + ' ...') + pyotherside.send("") + osType = platform.system() + if osType == "Linux": + pyotherside.send('-------->> You can visit the URL: http://'+get_ip_address(b'wlan0')+':'+str(port)+"at your computer") + else: + pyotherside.send('-------->> You can visit the URL: http://127.0.0.1:' +str(port)) + pyotherside.send("") + pyotherside.send('-------->> Have Fun ;)---------------- ') + pyotherside.send("") + return ('', port) + +serveraddr = showTips() + +def sizeof_fmt(num): + for x in ['bytes','KB','MB','GB']: + if num < 1024.0: + return "%3.1f%s" % (num, x) + num /= 1024.0 + return "%3.1f%s" % (num, 'TB') + +def modification_date(filename): + # t = os.path.getmtime(filename) + # return datetime.datetime.fromtimestamp(t) + return time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(os.path.getmtime(filename))) + +class SimpleHTTPRequestHandler(http.server.BaseHTTPRequestHandler): + + """Simple HTTP request handler with GET/HEAD/POST commands. + + This serves files from the current directory and any of its + subdirectories. The MIME type for files is determined by + calling the .guess_type() method. And can reveive file uploaded + by client. + + The GET/HEAD/POST requests are identical except that the HEAD + request omits the actual contents of the file. + + """ + + server_version = "SimpleHTTPWithUpload/" + __version__ + + def do_GET(self): + """Serve a GET request.""" + # print "....................", threading.currentThread().getName() + f = self.send_head() + if f: + for i in f.readlines(): + if isinstance(i,str): + self.wfile.write(i.encode("utf-8")) + else: + self.wfile.write(i) + #self.copyfile(f, self.wfile) + f.close() + + def do_HEAD(self): + """Serve a HEAD request.""" + f = self.send_head() + if f: + f.close() + + def do_POST(self): + """Serve a POST request.""" + r, info = self.deal_post_data() + print(r, info, "by: ", self.client_address) + f = StringIO() + f.write('') + f.write("\nUpload Result Page\n") + f.write("\n

Upload Result Page

\n") + f.write("
\n") + if r: + f.write("Success:") + else: + f.write("Failed:") + f.write(info) + f.write("
back" % self.headers['referer']) + f.write("
Powered By: bones7456, check new version at ") + f.write("") + f.write("here.\n\n") + length = f.tell() + f.seek(0) + self.send_response(200) + self.send_header("Content-type", "text/html") + self.send_header("Content-Length", str(length)) + self.end_headers() + if f: + for i in f.readlines(): + #self.copyfile(f, self.wfile) + self.wfile.write(i.encode("utf-8")) + f.close() + + def deal_post_data(self): + boundary = str(self.headers["Content-Type"].split("=")[1]).encode("utf-8") + remainbytes = int(self.headers['Content-length']) + line = self.rfile.readline() + remainbytes -= len(line) + if not boundary in line: + return (False, "Content NOT begin with boundary") + line = self.rfile.readline() + remainbytes -= len(line) + fn = re.findall(r'Content-Disposition.*name="file"; filename="(.*)"'.encode('utf-8'), line) + if not fn: + return (False, "Can't find out file name...") + path = str(self.translate_path(self.path)).encode('utf-8') + osType = platform.system() + try: + if osType == "Linux": + fn = os.path.join(path, fn[0].decode('gbk').encode('utf-8')) + else: + fn = os.path.join(path, fn[0]) + except Exception as e: + return (False, "文件名请不要用中文,或者使用IE上传中文名的文件。{}" .format(e)) + while os.path.exists(fn): + fn += "_".encode("utf-8") + line = self.rfile.readline() + remainbytes -= len(line) + line = self.rfile.readline() + remainbytes -= len(line) + try: + out = open(fn, 'wb') + except IOError: + return (False, "Can't create file to write, do you have permission to write?") + + preline = self.rfile.readline() + remainbytes -= len(preline) + while remainbytes > 0: + line = self.rfile.readline() + remainbytes -= len(line) + if boundary in line: + preline = preline[0:-1] + if preline.endswith('\r'.encode("utf-8")): + preline = preline[0:-1] + out.write(preline) + out.close() + return (True, "File '%s' upload success!" % fn) + else: + out.write(preline) + preline = line + return (False, "Unexpect Ends of data.") + + 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. + + """ + path = self.translate_path(self.path) + f = None + if os.path.isdir(path): + if not self.path.endswith('/'): + # redirect browser - doing basically what apache does + self.send_response(301) + self.send_header("Location", self.path + "/") + self.end_headers() + return None + 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) + fs = os.fstat(f.fileno()) + self.send_header("Content-Length", str(fs[6])) + self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) + self.end_headers() + return f + + def list_directory(self, path): + """Helper to produce a directory listing (absent index.html). + + Return value is either a file object, or None (indicating an + error). In either case, the headers are sent, making the + interface the same as for send_head(). + + """ + try: + list = os.listdir(path) + except os.error: + self.send_error(404, "No permission to list directory") + return None + list.sort(key=lambda a: a.lower()) + f = StringIO() + displaypath = cgi.escape(urllib.parse.unquote(self.path)) + f.write('') + f.write("\nDirectory listing for %s\n" % displaypath) + f.write("\n

Directory listing for %s

\n" % displaypath) + f.write("
\n") + f.write("
") + f.write("") + f.write("") + f.write("              ") + f.write("") + f.write("
\n") + f.write("
\n
    \n") + for name in list: + fullname = os.path.join(path, name) + colorName = displayname = linkname = name + # Append / for directories or @ for symbolic links + if os.path.isdir(fullname): + colorName = '' + name + '/' + displayname = name + linkname = name + "/" + if os.path.islink(fullname): + colorName = '' + name + '@' + displayname = name + # Note: a link to a directory displays with @ and links with / + filename = os.getcwd() + '/' + displaypath + displayname + f.write('\n' + % (urllib.parse.quote(linkname), colorName, + sizeof_fmt(os.path.getsize(filename)), modification_date(filename))) + f.write("
    %s%s%s
    \n
    \n\n\n") + length = f.tell() + f.seek(0) + self.send_response(200) + self.send_header("Content-type", "text/html") + self.send_header("Content-Length", str(length)) + self.end_headers() + return f + + def translate_path(self, path): + """Translate a /-separated PATH to the local filename syntax. + + Components that mean special things to the local file system + (e.g. drive or directory names) are ignored. (XXX They should + probably be diagnosed.) + + """ + # abandon query parameters + path = path.split('?',1)[0] + path = path.split('#',1)[0] + path = posixpath.normpath(urllib.parse.unquote(path)) + words = path.split('/') + words = [_f for _f in words if _f] + path = os.getcwd() + for word in words: + drive, word = os.path.splitdrive(word) + head, word = os.path.split(word) + if word in (os.curdir, os.pardir): continue + path = os.path.join(path, word) + return path + + def copyfile(self, source, outputfile): + """Copy all data between two file objects. + + The SOURCE argument is a file object open for reading + (or anything with a read() method) and the DESTINATION + argument is a file object open for writing (or + anything with a write() method). + + The only reason for overriding this would be to change + the block size or perhaps to replace newlines by CRLF + -- note however that this the default server uses this + to copy binary data as well. + + """ + shutil.copyfileobj(source, outputfile) + + def guess_type(self, path): + """Guess the type of a file. + + Argument is a PATH (a filename). + + Return value is a string of the form type/subtype, + usable for a MIME Content-type header. + + The default implementation looks the file's extension + up in the table self.extensions_map, using application/octet-stream + as a default; however it would be permissible (if + slow) to look inside the data to make a better guess. + + """ + + base, ext = posixpath.splitext(path) + if ext in self.extensions_map: + return self.extensions_map[ext] + ext = ext.lower() + if ext in self.extensions_map: + return self.extensions_map[ext] + else: + return self.extensions_map[''] + + if not mimetypes.inited: + mimetypes.init() # try to read system mime.types + extensions_map = mimetypes.types_map.copy() + extensions_map.update({ + '': 'application/octet-stream', # Default + '.py': 'text/plain', + '.c': 'text/plain', + '.h': 'text/plain', + }) + +class ThreadingServer(ThreadingMixIn, http.server.HTTPServer): + pass + +def test(HandlerClass = SimpleHTTPRequestHandler, + ServerClass = http.server.HTTPServer): + http.server.test(HandlerClass, ServerClass) + +def mymain(): + # test() + + #单线程 + # srvr = BaseHTTPServer.HTTPServer(serveraddr, SimpleHTTPRequestHandler) + + #多线程 + srvr = ThreadingServer(serveraddr, SimpleHTTPRequestHandler) + + srvr.serve_forever() +mymain() diff --git a/rpm/harbour-python3ftp.changes.in b/rpm/harbour-python3ftp.changes.in new file mode 100644 index 0000000..f134c40 --- /dev/null +++ b/rpm/harbour-python3ftp.changes.in @@ -0,0 +1,15 @@ +# Rename this file as harbour-python3ftp.changes to include changelog +# entries in your RPM file. +# +# Add new changelog entries following the format below. +# Add newest entries to the top of the list. +# Separate entries from eachother with a blank line. + +# * date Author's Name version-release +# - Summary of changes + +* Sun Apr 13 2014 Jack Tar 0.0.1-1 +- Scrubbed the deck +- Hoisted the sails + + diff --git a/rpm/harbour-python3ftp.spec b/rpm/harbour-python3ftp.spec new file mode 100644 index 0000000..c117f5f --- /dev/null +++ b/rpm/harbour-python3ftp.spec @@ -0,0 +1,72 @@ +# +# Do NOT Edit the Auto-generated Part! +# Generated by: spectacle version 0.27 +# + +Name: harbour-python3ftp + +# >> macros +# << macros + +%{!?qtc_qmake:%define qtc_qmake %qmake} +%{!?qtc_qmake5:%define qtc_qmake5 %qmake5} +%{!?qtc_make:%define qtc_make make} +%{?qtc_builddir:%define _builddir %qtc_builddir} +Summary: A ftp client by python3 +Version: 0.1 +Release: 1 +Group: Qt/Qt +License: LICENSE +URL: http://example.org/ +Source0: %{name}-%{version}.tar.bz2 +Source100: harbour-python3ftp.yaml +Requires: sailfishsilica-qt5 >= 0.10.9 +Requires: pyotherside-qml-plugin-python3-qt5 >= 1.3.0 +BuildRequires: pkgconfig(sailfishapp) >= 1.0.2 +BuildRequires: pkgconfig(Qt5Core) +BuildRequires: pkgconfig(Qt5Qml) +BuildRequires: pkgconfig(Qt5Quick) +BuildRequires: desktop-file-utils + +%description +Short description of my SailfishOS Application + + +%prep +%setup -q -n %{name}-%{version} + +# >> setup +# << setup + +%build +# >> build pre +# << build pre + +%qtc_qmake5 + +%qtc_make %{?_smp_mflags} + +# >> build post +# << build post + +%install +rm -rf %{buildroot} +# >> install pre +# << install pre +%qmake5_install + +# >> install post +# << install post + +desktop-file-install --delete-original \ + --dir %{buildroot}%{_datadir}/applications \ + %{buildroot}%{_datadir}/applications/*.desktop + +%files +%defattr(-,root,root,-) +%{_bindir} +%{_datadir}/%{name} +%{_datadir}/applications/%{name}.desktop +%{_datadir}/icons/hicolor/86x86/apps/%{name}.png +# >> files +# << files diff --git a/rpm/harbour-python3ftp.yaml b/rpm/harbour-python3ftp.yaml new file mode 100644 index 0000000..46c7c60 --- /dev/null +++ b/rpm/harbour-python3ftp.yaml @@ -0,0 +1,46 @@ +Name: harbour-python3ftp +Summary: A ftp client by python3 +Version: 0.1 +Release: 1 +# The contents of the Group field should be one of the groups listed here: +# http://gitorious.org/meego-developer-tools/spectacle/blobs/master/data/GROUPS +Group: Qt/Qt +URL: http://example.org/ +License: LICENSE +# This must be generated before uploading a package to a remote build service. +# Usually this line does not need to be modified. +Sources: +- '%{name}-%{version}.tar.bz2' +Description: | + Short description of my SailfishOS Application +Configure: none +# The qtc5 builder inserts macros to allow QtCreator to have fine +# control over qmake/make execution +Builder: qtc5 + +# This section specifies build dependencies that are resolved using pkgconfig. +# This is the preferred way of specifying build dependencies for your package. +PkgConfigBR: + - sailfishapp >= 1.0.2 + - Qt5Core + - Qt5Qml + - Qt5Quick + +# Build dependencies without a pkgconfig setup can be listed here +# PkgBR: +# - package-needed-to-build + +# Runtime dependencies which are not automatically detected +Requires: + - sailfishsilica-qt5 >= 0.10.9 + - pyotherside-qml-plugin-python3-qt5 >= 1.3.0 +# All installed files +Files: + - '%{_bindir}' + - '%{_datadir}/%{name}' + - '%{_datadir}/applications/%{name}.desktop' + - '%{_datadir}/icons/hicolor/86x86/apps/%{name}.png' + +# For more information about yaml and what's supported in Sailfish OS +# build system, please see https://wiki.merproject.org/wiki/Spectacle + diff --git a/src/harbour-python3ftp.cpp b/src/harbour-python3ftp.cpp new file mode 100644 index 0000000..2122a5a --- /dev/null +++ b/src/harbour-python3ftp.cpp @@ -0,0 +1,48 @@ +/* + Copyright (C) 2013 Jolla Ltd. + Contact: Thomas Perl + All rights reserved. + + You may use this file under the terms of BSD license as follows: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Jolla Ltd nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef QT_QML_DEBUG +#include +#endif + +#include + + +int main(int argc, char *argv[]) +{ + QGuiApplication* app = SailfishApp::application(argc, argv); + QQuickView* view = SailfishApp::createView(); + view->setSource(SailfishApp::pathTo("qml/harbour-python3ftp.qml")); + view->show(); + QObject::connect((QObject*)view->engine(), SIGNAL(quit()), app, SLOT(quit())); + + return app->exec(); +} + diff --git a/translations/harbour-python3ftp-de.ts b/translations/harbour-python3ftp-de.ts new file mode 100644 index 0000000..20a83db --- /dev/null +++ b/translations/harbour-python3ftp-de.ts @@ -0,0 +1,41 @@ + + + + + CoverPage + + My Cover + Mein Cover + + + + FirstPage + + Show Page 2 + Zur Seite 2 + + + UI Template + UI-Vorlage + + + Hello Sailors + Hallo Matrosen + + + Python FTP + + + + + SecondPage + + Nested Page + Unterseite + + + Item + Element + + + diff --git a/translations/harbour-python3ftp.ts b/translations/harbour-python3ftp.ts new file mode 100644 index 0000000..49db313 --- /dev/null +++ b/translations/harbour-python3ftp.ts @@ -0,0 +1,11 @@ + + + + + FirstPage + + Python FTP + + + +