-rw-r--r-- | core/qws/TODO | 31 | ||||
-rw-r--r-- | core/qws/config.in | 16 | ||||
-rw-r--r-- | core/qws/main.cpp | 71 | ||||
-rw-r--r-- | core/qws/opie-qws.control | 10 | ||||
-rw-r--r-- | core/qws/oqwsserver.cpp | 196 | ||||
-rw-r--r-- | core/qws/oqwsserver.h | 57 | ||||
-rw-r--r-- | core/qws/qcopbridge.cpp | 422 | ||||
-rw-r--r-- | core/qws/qcopbridge.h | 92 | ||||
-rw-r--r-- | core/qws/qws.pro | 20 | ||||
-rw-r--r-- | core/qws/transferserver.cpp | 1424 | ||||
-rw-r--r-- | core/qws/transferserver.h | 179 |
11 files changed, 2518 insertions, 0 deletions
diff --git a/core/qws/TODO b/core/qws/TODO new file mode 100644 index 0000000..b35d87e --- a/dev/null +++ b/core/qws/TODO | |||
@@ -0,0 +1,31 @@ | |||
1 | New Launcher TODO: | ||
2 | |||
3 | [x] Split QWS Server out of launcher/taskbar application | ||
4 | [ ] Handling of default Opie env vars that may or may not be | ||
5 | affected by ODevice. This should really affect all Opie apps.. | ||
6 | perhaps in qpeapplication, or a seperate app that sets the env vars | ||
7 | for Opie ala the way ssh-agent outputs an eval'able set of vars. | ||
8 | |||
9 | [.] QWS Server | ||
10 | [x] actual qws server (qpeapplication as GuiServer) | ||
11 | [x] qcop bridge | ||
12 | [x] transfer server (sync compatibility) | ||
13 | [ ] calibration QCop calls (to split calibration into a seperate app) | ||
14 | [ ] window list / management QCop calls (matchbox style task switching) | ||
15 | [ ] qws event filter hooks | ||
16 | [ ] Touch and Key clicks | ||
17 | [ ] xstroke style input | ||
18 | |||
19 | [ ] Launcher/Taskbar | ||
20 | [ ] Proper VT handling, and VT switching - qt/e + qpeapplication.. every app needs to handle this properly | ||
21 | [ ] Proper timezone handling (create localtime link) - belongs in that which handles the time. clock applet, systemtime. | ||
22 | [ ] LauncherView as plugins, possibly allow the plugin to add any | ||
23 | arbitary number of tabs, in which case the launcher is simply | ||
24 | a tab bar with plugins, the default being the AppLnk and Docs | ||
25 | scanning plugins, to give us the current functionality. | ||
26 | |||
27 | [ ] Uncertain | ||
28 | [ ] Alerts - mem and battery | ||
29 | [ ] OpieScreenSaver | ||
30 | [.] package slave - essentially take bridged qcop message, pass it | ||
31 | along to the app which is associated with the .ipk mime type. | ||
diff --git a/core/qws/config.in b/core/qws/config.in new file mode 100644 index 0000000..1316c77 --- a/dev/null +++ b/core/qws/config.in | |||
@@ -0,0 +1,16 @@ | |||
1 | config QWS | ||
2 | boolean "Minimal QWS Server" | ||
3 | default "n" | ||
4 | depends ( LIBQPE || LIBQPE-X11 ) && LIBOPIE | ||
5 | |||
6 | # menu "Advanced QWS Server Config" | ||
7 | # config QWS_QCOP | ||
8 | # bool "QCop bridge and Transfer server (sync)" | ||
9 | # default y | ||
10 | # depends on QWS | ||
11 | # | ||
12 | # config QWS_PACKAGE | ||
13 | # bool "Package Slave (package installs via sync software)" | ||
14 | # default n | ||
15 | # depends on QWS | ||
16 | # endmenu | ||
diff --git a/core/qws/main.cpp b/core/qws/main.cpp new file mode 100644 index 0000000..bfed283 --- a/dev/null +++ b/core/qws/main.cpp | |||
@@ -0,0 +1,71 @@ | |||
1 | #include <qwindowsystem_qws.h> | ||
2 | #include <qapplication.h> | ||
3 | |||
4 | #include "oqwsserver.h" | ||
5 | |||
6 | #include <sys/types.h> | ||
7 | #include <sys/stat.h> | ||
8 | #include <fcntl.h> | ||
9 | #include <unistd.h> | ||
10 | |||
11 | #include <syslog.h> | ||
12 | #include <stdio.h> | ||
13 | |||
14 | #define APPNAME "op-qws" | ||
15 | |||
16 | void toSyslog(QtMsgType type, const char *msg) | ||
17 | { | ||
18 | int level = LOG_INFO; | ||
19 | switch (type) { | ||
20 | case QtDebugMsg: | ||
21 | level = LOG_DEBUG; | ||
22 | break; | ||
23 | case QtWarningMsg: | ||
24 | level = LOG_WARNING; | ||
25 | break; | ||
26 | case QtFatalMsg: | ||
27 | level = LOG_ERR; | ||
28 | break; | ||
29 | } | ||
30 | syslog (LOG_DAEMON | level, msg); | ||
31 | } | ||
32 | |||
33 | int daemon_init(void) | ||
34 | { | ||
35 | pid_t pid; | ||
36 | |||
37 | if ((pid = fork()) < 0) | ||
38 | return(-1); | ||
39 | else if (pid != 0) | ||
40 | exit(0); | ||
41 | |||
42 | setsid(); | ||
43 | |||
44 | chdir("/"); | ||
45 | |||
46 | umask(0); | ||
47 | |||
48 | fclose(stdout); | ||
49 | fclose(stderr); | ||
50 | fclose(stdin); | ||
51 | |||
52 | return(0); | ||
53 | } | ||
54 | |||
55 | int main( int argc, char ** argv ) | ||
56 | { | ||
57 | while (argc > 1) { | ||
58 | if (strcmp(argv[--argc], "-d") == 0) { | ||
59 | // daemonize | ||
60 | openlog(APPNAME, 0, LOG_DAEMON); | ||
61 | qInstallMsgHandler(toSyslog); | ||
62 | if (daemon_init() != 0) { | ||
63 | fprintf(stderr, "%s: Error: Unable to daemonize\n", APPNAME); | ||
64 | return 1; | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | |||
69 | OQWSServer a(argc, argv, QApplication::GuiServer); | ||
70 | return a.exec(); | ||
71 | } | ||
diff --git a/core/qws/opie-qws.control b/core/qws/opie-qws.control new file mode 100644 index 0000000..fe5f4e0 --- a/dev/null +++ b/core/qws/opie-qws.control | |||
@@ -0,0 +1,10 @@ | |||
1 | Package: opie-taskbar | ||
2 | Files: bin/qpe apps/Settings/Calibrate.desktop pics/launcher pics/devicebuttons/*.png plugins/applets/libsuspendapplet.so* plugins/applets/libhomeapplet.so* plugins/applets/liblogoutapplet.so* plugins/applets/librotateapplet.so* root/etc/init.d/opie | ||
3 | Priority: required | ||
4 | Section: opie/system | ||
5 | Maintainer: Project Opie <opie@handhelds.org> | ||
6 | Architecture: arm | ||
7 | Version: $QPE_VERSION-$SUB_VERSION.3 | ||
8 | Depends: task-opie-minimal | ||
9 | Replaces: opie-rotation | ||
10 | Description: Launcher for Opie | ||
diff --git a/core/qws/oqwsserver.cpp b/core/qws/oqwsserver.cpp new file mode 100644 index 0000000..1c61d19 --- a/dev/null +++ b/core/qws/oqwsserver.cpp | |||
@@ -0,0 +1,196 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | |||
21 | #include <syslog.h> | ||
22 | |||
23 | #include "oqwsserver.h" | ||
24 | #include "qcopbridge.h" | ||
25 | #include "transferserver.h" | ||
26 | |||
27 | #include <qpe/applnk.h> | ||
28 | #include <qpe/mimetype.h> | ||
29 | #include <qpe/password.h> | ||
30 | #include <qpe/config.h> | ||
31 | #include <qpe/power.h> | ||
32 | #include <qpe/timeconversion.h> | ||
33 | #include <qpe/qcopenvelope_qws.h> | ||
34 | #include <qpe/network.h> | ||
35 | #include <qpe/global.h> | ||
36 | |||
37 | #if defined( QT_QWS_SL5XXX ) || defined( QT_QWS_IPAQ ) | ||
38 | #include <qpe/custom.h> | ||
39 | #endif | ||
40 | |||
41 | #include <opie/odevice.h> | ||
42 | |||
43 | #include <qgfx_qws.h> | ||
44 | #include <qmainwindow.h> | ||
45 | #include <qmessagebox.h> | ||
46 | #include <qtimer.h> | ||
47 | #include <qwindowsystem_qws.h> | ||
48 | |||
49 | #include <qvaluelist.h> | ||
50 | |||
51 | #include <stdlib.h> | ||
52 | #include <unistd.h> | ||
53 | #include <fcntl.h> | ||
54 | |||
55 | using namespace Opie; | ||
56 | |||
57 | OQWSServer::OQWSServer( int& argc, char **argv, Type appType ) | ||
58 | : QPEApplication( argc, argv, appType ) | ||
59 | { | ||
60 | startServers(); | ||
61 | } | ||
62 | |||
63 | OQWSServer::~OQWSServer() | ||
64 | { | ||
65 | terminateServers(); | ||
66 | } | ||
67 | |||
68 | bool OQWSServer::eventFilter ( QObject *o, QEvent *e ) | ||
69 | { | ||
70 | #if 0 | ||
71 | if ( e-> type ( ) == QEvent::KeyPress || e-> type ( ) == QEvent::KeyRelease ) { | ||
72 | QKeyEvent *ke = (QKeyEvent *) e; | ||
73 | |||
74 | const ODeviceButton *db = ODevice::inst ( )-> buttonForKeycode ( ke-> key ( )); | ||
75 | |||
76 | if ( db ) { | ||
77 | if (checkButtonAction ( db, ke-> key ( ), e-> type ( ) == QEvent::KeyPress, ke-> isAutoRepeat ( ))) | ||
78 | return true; //checkButtonAction retrune false if events should be routed through | ||
79 | } | ||
80 | } | ||
81 | #endif | ||
82 | return QPEApplication::eventFilter ( o, e ); | ||
83 | } | ||
84 | |||
85 | #ifdef Q_WS_QWS | ||
86 | |||
87 | bool OQWSServer::qwsEventFilter( QWSEvent *e ) | ||
88 | { | ||
89 | #if 0 | ||
90 | qpedesktop->checkMemory(); | ||
91 | |||
92 | if ( e->type == QWSEvent::Key ) { | ||
93 | QWSKeyEvent * ke = (QWSKeyEvent *) e; | ||
94 | ushort keycode = ke-> simpleData. keycode; | ||
95 | |||
96 | if ( !loggedin && keycode != Key_F34 ) | ||
97 | return true; | ||
98 | |||
99 | bool press = ke-> simpleData. is_press; | ||
100 | bool autoRepeat = ke-> simpleData. is_auto_repeat; | ||
101 | |||
102 | if ( !keyboardGrabbed ( )) { | ||
103 | // app that registers key/message to be sent back to the app, when it doesn't have focus, | ||
104 | // when user presses key, unless keyboard has been requested from app. | ||
105 | // will not send multiple repeats if user holds key | ||
106 | // i.e. one shot | ||
107 | |||
108 | if ( keycode != 0 && press && !autoRepeat ) { | ||
109 | for ( KeyRegisterList::Iterator it = keyRegisterList.begin(); it != keyRegisterList.end(); ++it ) { | ||
110 | if (( *it ). getKeyCode ( ) == keycode ) { | ||
111 | QCopEnvelope (( *it ). getChannel ( ), ( *it ). getMessage ( )); | ||
112 | return true; | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
118 | if ( keycode == HardKey_Suspend ) { | ||
119 | if ( press ) | ||
120 | emit power ( ); | ||
121 | return true; | ||
122 | } | ||
123 | else if ( keycode == HardKey_Backlight ) { | ||
124 | if ( press ) | ||
125 | emit backlight ( ); | ||
126 | return true; | ||
127 | } | ||
128 | else if ( keycode == Key_F32 ) { | ||
129 | if ( press ) | ||
130 | QCopEnvelope e( "QPE/Desktop", "startSync()" ); | ||
131 | return true; | ||
132 | } | ||
133 | else if ( keycode == Key_F31 && !ke-> simpleData. modifiers ) { // Symbol Key -> show Unicode IM | ||
134 | if ( press ) | ||
135 | emit symbol ( ); | ||
136 | return true; | ||
137 | } | ||
138 | else if ( keycode == Key_NumLock ) { | ||
139 | if ( press ) | ||
140 | emit numLockStateToggle ( ); | ||
141 | } | ||
142 | else if ( keycode == Key_CapsLock ) { | ||
143 | if ( press ) | ||
144 | emit capsLockStateToggle(); | ||
145 | } | ||
146 | if (( press && !autoRepeat ) || ( !press && autoRepeat )) { | ||
147 | if ( m_keyclick_sound ) | ||
148 | ODevice::inst ( )-> keySound ( ); | ||
149 | } | ||
150 | } | ||
151 | else if ( e-> type == QWSEvent::Mouse ) { | ||
152 | QWSMouseEvent * me = ( QWSMouseEvent * ) e; | ||
153 | static bool up = true; | ||
154 | |||
155 | if ( me-> simpleData. state & LeftButton ) { | ||
156 | if ( up ) { | ||
157 | up = false; | ||
158 | if ( m_screentap_sound ) | ||
159 | ODevice::inst ( ) -> touchSound ( ); | ||
160 | } | ||
161 | } | ||
162 | else { | ||
163 | up = true; | ||
164 | } | ||
165 | } | ||
166 | #endif | ||
167 | return QPEApplication::qwsEventFilter ( e ); | ||
168 | } | ||
169 | |||
170 | #endif | ||
171 | |||
172 | void OQWSServer::startServers() | ||
173 | { | ||
174 | // start qcop bridge server | ||
175 | m_qcopBridge = new QCopBridge( 4243 ); | ||
176 | if ( !m_qcopBridge->ok() ) { | ||
177 | delete m_qcopBridge; | ||
178 | m_qcopBridge = 0; | ||
179 | } | ||
180 | // start transfer server | ||
181 | m_transferServer = new TransferServer( 4242 ); | ||
182 | if ( !m_transferServer->ok() ) { | ||
183 | delete m_transferServer; | ||
184 | m_transferServer = 0; | ||
185 | } | ||
186 | //if ( !transferServer || !qcopBridge ) | ||
187 | // startTimer( 2000 ); | ||
188 | } | ||
189 | |||
190 | void OQWSServer::terminateServers() | ||
191 | { | ||
192 | delete m_transferServer; | ||
193 | delete m_qcopBridge; | ||
194 | m_transferServer = 0; | ||
195 | m_qcopBridge = 0; | ||
196 | } | ||
diff --git a/core/qws/oqwsserver.h b/core/qws/oqwsserver.h new file mode 100644 index 0000000..b95c3fb --- a/dev/null +++ b/core/qws/oqwsserver.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | |||
21 | #ifndef __DESKTOP_H__ | ||
22 | #define __DESKTOP_H__ | ||
23 | |||
24 | |||
25 | #include <qpe/qpeapplication.h> | ||
26 | #include <opie/odevicebutton.h> | ||
27 | |||
28 | #include <qwidget.h> | ||
29 | #include <qdatetime.h> | ||
30 | |||
31 | class QCopBridge; | ||
32 | class TransferServer; | ||
33 | |||
34 | class OQWSServer : public QPEApplication | ||
35 | { | ||
36 | Q_OBJECT | ||
37 | public: | ||
38 | OQWSServer( int& argc, char **argv, Type t ); | ||
39 | ~OQWSServer(); | ||
40 | |||
41 | protected: | ||
42 | virtual bool eventFilter ( QObject *o, QEvent *e ); | ||
43 | |||
44 | #ifdef Q_WS_QWS | ||
45 | bool qwsEventFilter( QWSEvent * ); | ||
46 | #endif | ||
47 | |||
48 | private: | ||
49 | void startServers(); | ||
50 | void terminateServers(); | ||
51 | |||
52 | QCopBridge *m_qcopBridge; | ||
53 | TransferServer *m_transferServer; | ||
54 | }; | ||
55 | |||
56 | #endif // __DESKTOP_H__ | ||
57 | |||
diff --git a/core/qws/qcopbridge.cpp b/core/qws/qcopbridge.cpp new file mode 100644 index 0000000..6177a7c --- a/dev/null +++ b/core/qws/qcopbridge.cpp | |||
@@ -0,0 +1,422 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of the Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | |||
21 | #include "qcopbridge.h" | ||
22 | #include "transferserver.h" | ||
23 | |||
24 | #include <qpe/qcopenvelope_qws.h> | ||
25 | #include <qpe/qpeapplication.h> | ||
26 | #include <qpe/version.h> | ||
27 | |||
28 | #include <qdir.h> | ||
29 | #include <qfile.h> | ||
30 | #include <qtextstream.h> | ||
31 | #include <qdatastream.h> | ||
32 | #include <qstringlist.h> | ||
33 | #include <qfileinfo.h> | ||
34 | #include <qregexp.h> | ||
35 | #ifdef QWS | ||
36 | #include <qcopchannel_qws.h> | ||
37 | #endif | ||
38 | |||
39 | #define _XOPEN_SOURCE | ||
40 | #include <pwd.h> | ||
41 | #include <sys/types.h> | ||
42 | #include <unistd.h> | ||
43 | |||
44 | #if defined(_OS_LINUX_) | ||
45 | #include <shadow.h> | ||
46 | #endif | ||
47 | |||
48 | //#define INSECURE | ||
49 | |||
50 | const int block_size = 51200; | ||
51 | |||
52 | QCopBridge::QCopBridge( Q_UINT16 port, QObject *parent , | ||
53 | const char* name ) | ||
54 | : QServerSocket( port, 1, parent, name ), | ||
55 | desktopChannel( 0 ), | ||
56 | cardChannel( 0 ) | ||
57 | { | ||
58 | if ( !ok() ) | ||
59 | qWarning( "Failed to bind to port %d", port ); | ||
60 | else { | ||
61 | #ifndef QT_NO_COP | ||
62 | desktopChannel = new QCopChannel( "QPE/Desktop", this ); | ||
63 | connect( desktopChannel, SIGNAL(received(const QCString &, const QByteArray &)), | ||
64 | this, SLOT(desktopMessage( const QCString &, const QByteArray &)) ); | ||
65 | cardChannel = new QCopChannel( "QPE/Card", this ); | ||
66 | connect( cardChannel, SIGNAL(received(const QCString &, const QByteArray &)), | ||
67 | this, SLOT(desktopMessage( const QCString &, const QByteArray &)) ); | ||
68 | #endif | ||
69 | } | ||
70 | sendSync = FALSE; | ||
71 | } | ||
72 | |||
73 | QCopBridge::~QCopBridge() | ||
74 | { | ||
75 | #ifndef QT_NO_COP | ||
76 | delete desktopChannel; | ||
77 | #endif | ||
78 | } | ||
79 | |||
80 | void QCopBridge::newConnection( int socket ) | ||
81 | { | ||
82 | QCopBridgePI *pi = new QCopBridgePI( socket, this ); | ||
83 | openConnections.append( pi ); | ||
84 | connect ( pi, SIGNAL( connectionClosed( QCopBridgePI *) ), this, SLOT( connectionClosed( QCopBridgePI *) ) ); | ||
85 | #ifndef QT_NO_COP | ||
86 | QCopEnvelope( "QPE/System", "setScreenSaverMode(int)" ) << QPEApplication::DisableSuspend; | ||
87 | #endif | ||
88 | |||
89 | if ( sendSync ) { | ||
90 | pi ->startSync(); | ||
91 | sendSync = FALSE; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | void QCopBridge::connectionClosed( QCopBridgePI *pi ) | ||
96 | { | ||
97 | openConnections.remove( pi ); | ||
98 | if ( openConnections.count() == 0 ) { | ||
99 | #ifndef QT_NO_COP | ||
100 | QCopEnvelope( "QPE/System", "setScreenSaverMode(int)" ) << QPEApplication::Enable; | ||
101 | #endif | ||
102 | } | ||
103 | } | ||
104 | |||
105 | void QCopBridge::closeOpenConnections() | ||
106 | { | ||
107 | QCopBridgePI *pi; | ||
108 | for ( pi = openConnections.first(); pi != 0; pi = openConnections.next() ) | ||
109 | pi->close(); | ||
110 | } | ||
111 | |||
112 | |||
113 | void QCopBridge::desktopMessage( const QCString &command, const QByteArray &args ) | ||
114 | { | ||
115 | command.stripWhiteSpace(); | ||
116 | |||
117 | int paren = command.find( "(" ); | ||
118 | if ( paren <= 0 ) { | ||
119 | qDebug("DesktopMessage: bad qcop syntax"); | ||
120 | return; | ||
121 | } | ||
122 | |||
123 | QString params = command.mid( paren + 1 ); | ||
124 | if ( params[params.length()-1] != ')' ) { | ||
125 | qDebug("DesktopMessage: bad qcop syntax"); | ||
126 | return; | ||
127 | } | ||
128 | |||
129 | params.truncate( params.length()-1 ); | ||
130 | |||
131 | QStringList paramList = QStringList::split( ",", params ); | ||
132 | QString data; | ||
133 | if ( paramList.count() ) { | ||
134 | QDataStream stream( args, IO_ReadOnly ); | ||
135 | for ( QStringList::Iterator it = paramList.begin(); it != paramList.end(); ++it ) { | ||
136 | QString str; | ||
137 | if ( *it == "QString" ) { | ||
138 | stream >> str; | ||
139 | } else if ( *it == "QCString" ) { | ||
140 | QCString cstr; | ||
141 | stream >> cstr; | ||
142 | str = QString::fromLocal8Bit( cstr ); | ||
143 | } else if ( *it == "int" ) { | ||
144 | int i; | ||
145 | stream >> i; | ||
146 | str = QString::number( i ); | ||
147 | } else if ( *it == "bool" ) { | ||
148 | int i; | ||
149 | stream >> i; | ||
150 | str = QString::number( i ); | ||
151 | } else { | ||
152 | qDebug(" cannot route the argument type %s throught the qcop bridge", (*it).latin1() ); | ||
153 | return; | ||
154 | } | ||
155 | QString estr; | ||
156 | for (int i=0; i<(int)str.length(); i++) { | ||
157 | QChar ch = str[i]; | ||
158 | if ( ch.row() ) | ||
159 | goto quick; | ||
160 | switch (ch.cell()) { | ||
161 | case '&': | ||
162 | estr.append( "&" ); | ||
163 | break; | ||
164 | case ' ': | ||
165 | estr.append( "&0x20;" ); | ||
166 | break; | ||
167 | case '\n': | ||
168 | estr.append( "&0x0d;" ); | ||
169 | break; | ||
170 | case '\r': | ||
171 | estr.append( "&0x0a;" ); | ||
172 | break; | ||
173 | default: quick: | ||
174 | estr.append(ch); | ||
175 | } | ||
176 | } | ||
177 | data += " " + estr; | ||
178 | } | ||
179 | } | ||
180 | QString sendCommand = QString(command.data()) + data; | ||
181 | // send the command to all open connections | ||
182 | if ( command == "startSync()" ) { | ||
183 | // we need to buffer it a bit | ||
184 | sendSync = TRUE; | ||
185 | startTimer( 20000 ); | ||
186 | } | ||
187 | |||
188 | QCopBridgePI *pi; | ||
189 | for ( pi = openConnections.first(); pi != 0; pi = openConnections.next() ) { | ||
190 | pi->sendDesktopMessage( sendCommand ); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | void QCopBridge::timerEvent( QTimerEvent * ) | ||
195 | { | ||
196 | sendSync = FALSE; | ||
197 | killTimers(); | ||
198 | } | ||
199 | |||
200 | |||
201 | QCopBridgePI::QCopBridgePI( int socket, QObject *parent , const char* name ) | ||
202 | : QSocket( parent, name ) | ||
203 | { | ||
204 | setSocket( socket ); | ||
205 | |||
206 | peerport = peerPort(); | ||
207 | peeraddress = peerAddress(); | ||
208 | |||
209 | #ifndef INSECURE | ||
210 | if ( !SyncAuthentication::isAuthorized(peeraddress) ) { | ||
211 | state = Forbidden; | ||
212 | startTimer( 0 ); | ||
213 | } else | ||
214 | #endif | ||
215 | { | ||
216 | state = Connected; | ||
217 | sendSync = FALSE; | ||
218 | connect( this, SIGNAL( readyRead() ), SLOT( read() ) ); | ||
219 | connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); | ||
220 | |||
221 | QString intro="220 Qtopia "; | ||
222 | intro += QPE_VERSION; intro += ";"; | ||
223 | intro += "challenge="; intro += SyncAuthentication::serverId(); intro += ";"; | ||
224 | intro += "loginname="; intro += SyncAuthentication::loginName(); intro += ";"; | ||
225 | intro += "displayname="; intro += SyncAuthentication::ownerName(); intro += ";"; | ||
226 | send( intro ); | ||
227 | state = Wait_USER; | ||
228 | |||
229 | // idle timer to close connections when not used anymore | ||
230 | startTimer( 60000 ); | ||
231 | connected = TRUE; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | |||
236 | QCopBridgePI::~QCopBridgePI() | ||
237 | { | ||
238 | |||
239 | } | ||
240 | |||
241 | void QCopBridgePI::connectionClosed() | ||
242 | { | ||
243 | emit connectionClosed( this ); | ||
244 | // qDebug( "Debug: Connection closed" ); | ||
245 | delete this; | ||
246 | } | ||
247 | |||
248 | void QCopBridgePI::sendDesktopMessage( const QString &msg ) | ||
249 | { | ||
250 | QString str = "CALL QPE/Desktop " + msg; | ||
251 | send ( str ); | ||
252 | } | ||
253 | |||
254 | |||
255 | void QCopBridgePI::send( const QString& msg ) | ||
256 | { | ||
257 | QTextStream os( this ); | ||
258 | os << msg << endl; | ||
259 | //qDebug( "sending qcop message: %s", msg.latin1() ); | ||
260 | } | ||
261 | |||
262 | void QCopBridgePI::read() | ||
263 | { | ||
264 | while ( canReadLine() ) | ||
265 | process( readLine().stripWhiteSpace() ); | ||
266 | } | ||
267 | |||
268 | void QCopBridgePI::process( const QString& message ) | ||
269 | { | ||
270 | //qDebug( "Command: %s", message.latin1() ); | ||
271 | |||
272 | // split message using "," as separator | ||
273 | QStringList msg = QStringList::split( " ", message ); | ||
274 | if ( msg.isEmpty() ) return; | ||
275 | |||
276 | // command token | ||
277 | QString cmd = msg[0].upper(); | ||
278 | |||
279 | // argument token | ||
280 | QString arg; | ||
281 | if ( msg.count() >= 2 ) | ||
282 | arg = msg[1]; | ||
283 | |||
284 | // we always respond to QUIT, regardless of state | ||
285 | if ( cmd == "QUIT" ) { | ||
286 | send( "211 Have a nice day!" ); | ||
287 | delete this; | ||
288 | return; | ||
289 | } | ||
290 | |||
291 | // connected to client | ||
292 | if ( Connected == state ) | ||
293 | return; | ||
294 | |||
295 | // waiting for user name | ||
296 | if ( Wait_USER == state ) { | ||
297 | |||
298 | if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) { | ||
299 | send( "530 Please login with USER and PASS" ); | ||
300 | return; | ||
301 | } | ||
302 | send( "331 User name ok, need password" ); | ||
303 | state = Wait_PASS; | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | // waiting for password | ||
308 | if ( Wait_PASS == state ) { | ||
309 | |||
310 | if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) { | ||
311 | send( "530 Please login with USER and PASS" ); | ||
312 | return; | ||
313 | } | ||
314 | send( "230 User logged in, proceed" ); | ||
315 | state = Ready; | ||
316 | if ( sendSync ) { | ||
317 | sendDesktopMessage( "startSync()" ); | ||
318 | sendSync = FALSE; | ||
319 | } | ||
320 | return; | ||
321 | } | ||
322 | |||
323 | // noop (NOOP) | ||
324 | else if ( cmd == "NOOP" ) { | ||
325 | connected = TRUE; | ||
326 | send( "200 Command okay" ); | ||
327 | } | ||
328 | |||
329 | // call (CALL) | ||
330 | else if ( cmd == "CALL" ) { | ||
331 | |||
332 | // example: call QPE/System execute(QString) addressbook | ||
333 | |||
334 | if ( msg.count() < 3 ) { | ||
335 | send( "500 Syntax error, command unrecognized" ); | ||
336 | } | ||
337 | else { | ||
338 | |||
339 | QString channel = msg[1]; | ||
340 | QString command = msg[2]; | ||
341 | |||
342 | command.stripWhiteSpace(); | ||
343 | |||
344 | int paren = command.find( "(" ); | ||
345 | if ( paren <= 0 ) { | ||
346 | send( "500 Syntax error, command unrecognized" ); | ||
347 | return; | ||
348 | } | ||
349 | |||
350 | QString params = command.mid( paren + 1 ); | ||
351 | if ( params[params.length()-1] != ')' ) { | ||
352 | send( "500 Syntax error, command unrecognized" ); | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | params.truncate( params.length()-1 ); | ||
357 | QByteArray buffer; | ||
358 | QDataStream ds( buffer, IO_WriteOnly ); | ||
359 | |||
360 | int msgId = 3; | ||
361 | |||
362 | QStringList paramList = QStringList::split( ",", params ); | ||
363 | if ( paramList.count() > msg.count() - 3 ) { | ||
364 | send( "500 Syntax error, command unrecognized" ); | ||
365 | return; | ||
366 | } | ||
367 | |||
368 | for ( QStringList::Iterator it = paramList.begin(); it != paramList.end(); ++it ) { | ||
369 | |||
370 | QString arg = msg[msgId]; | ||
371 | arg.replace( QRegExp("&0x20;"), " " ); | ||
372 | arg.replace( QRegExp("&"), "&" ); | ||
373 | arg.replace( QRegExp("&0x0d;"), "\n" ); | ||
374 | arg.replace( QRegExp("&0x0a;"), "\r" ); | ||
375 | if ( *it == "QString" ) | ||
376 | ds << arg; | ||
377 | else if ( *it == "QCString" ) | ||
378 | ds << arg.local8Bit(); | ||
379 | else if ( *it == "int" ) | ||
380 | ds << arg.toInt(); | ||
381 | else if ( *it == "bool" ) | ||
382 | ds << arg.toInt(); | ||
383 | else { | ||
384 | send( "500 Syntax error, command unrecognized" ); | ||
385 | return; | ||
386 | } | ||
387 | msgId++; | ||
388 | } | ||
389 | |||
390 | #ifndef QT_NO_COP | ||
391 | if ( !QCopChannel::isRegistered( channel.latin1() ) ) { | ||
392 | // send message back about it | ||
393 | QString answer = "599 ChannelNotRegistered " + channel; | ||
394 | send( answer ); | ||
395 | return; | ||
396 | } | ||
397 | #endif | ||
398 | |||
399 | #ifndef QT_NO_COP | ||
400 | if ( paramList.count() ) | ||
401 | QCopChannel::send( channel.latin1(), command.latin1(), buffer ); | ||
402 | else | ||
403 | QCopChannel::send( channel.latin1(), command.latin1() ); | ||
404 | |||
405 | send( "200 Command okay" ); | ||
406 | #endif | ||
407 | } | ||
408 | } | ||
409 | // not implemented | ||
410 | else | ||
411 | send( "502 Command not implemented" ); | ||
412 | } | ||
413 | |||
414 | |||
415 | |||
416 | void QCopBridgePI::timerEvent( QTimerEvent * ) | ||
417 | { | ||
418 | if ( connected ) | ||
419 | connected = FALSE; | ||
420 | else | ||
421 | connectionClosed(); | ||
422 | } | ||
diff --git a/core/qws/qcopbridge.h b/core/qws/qcopbridge.h new file mode 100644 index 0000000..408d10d --- a/dev/null +++ b/core/qws/qcopbridge.h | |||
@@ -0,0 +1,92 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of the Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | #ifndef __qcopbridge_h__ | ||
21 | #define __qcopbridge_h__ | ||
22 | |||
23 | #include <qserversocket.h> | ||
24 | #include <qsocket.h> | ||
25 | #include <qdir.h> | ||
26 | #include <qfile.h> | ||
27 | #include <qbuffer.h> | ||
28 | |||
29 | class QFileInfo; | ||
30 | class QCopBridgePI; | ||
31 | class QCopChannel; | ||
32 | |||
33 | class QCopBridge : public QServerSocket | ||
34 | { | ||
35 | Q_OBJECT | ||
36 | |||
37 | public: | ||
38 | QCopBridge( Q_UINT16 port, QObject *parent = 0, const char* name = 0 ); | ||
39 | virtual ~QCopBridge(); | ||
40 | |||
41 | void newConnection( int socket ); | ||
42 | void closeOpenConnections(); | ||
43 | |||
44 | public slots: | ||
45 | void connectionClosed( QCopBridgePI *pi ); | ||
46 | void desktopMessage( const QCString &call, const QByteArray & ); | ||
47 | |||
48 | protected: | ||
49 | void timerEvent( QTimerEvent * ); | ||
50 | |||
51 | private: | ||
52 | QCopChannel *desktopChannel; | ||
53 | QCopChannel *cardChannel; | ||
54 | QList<QCopBridgePI> openConnections; | ||
55 | bool sendSync; | ||
56 | }; | ||
57 | |||
58 | |||
59 | class QCopBridgePI : public QSocket | ||
60 | { | ||
61 | Q_OBJECT | ||
62 | |||
63 | enum State { Connected, Wait_USER, Wait_PASS, Ready, Forbidden }; | ||
64 | |||
65 | public: | ||
66 | QCopBridgePI( int socket, QObject *parent = 0, const char* name = 0 ); | ||
67 | virtual ~QCopBridgePI(); | ||
68 | |||
69 | void sendDesktopMessage( const QString &msg ); | ||
70 | void startSync() { sendSync = TRUE; } | ||
71 | |||
72 | signals: | ||
73 | void connectionClosed( QCopBridgePI *); | ||
74 | |||
75 | protected slots: | ||
76 | void read(); | ||
77 | void send( const QString& msg ); | ||
78 | void process( const QString& command ); | ||
79 | void connectionClosed(); | ||
80 | |||
81 | protected: | ||
82 | void timerEvent( QTimerEvent *e ); | ||
83 | |||
84 | private: | ||
85 | State state; | ||
86 | Q_UINT16 peerport; | ||
87 | QHostAddress peeraddress; | ||
88 | bool connected; | ||
89 | bool sendSync; | ||
90 | }; | ||
91 | |||
92 | #endif | ||
diff --git a/core/qws/qws.pro b/core/qws/qws.pro new file mode 100644 index 0000000..5656a59 --- a/dev/null +++ b/core/qws/qws.pro | |||
@@ -0,0 +1,20 @@ | |||
1 | TEMPLATE= app | ||
2 | CONFIG = qt warn_on release | ||
3 | DESTDIR = $(OPIEDIR)/bin | ||
4 | |||
5 | HEADERS = \ | ||
6 | transferserver.h \ | ||
7 | qcopbridge.h \ | ||
8 | oqwsserver.h | ||
9 | SOURCES = \ | ||
10 | main.cpp \ | ||
11 | transferserver.cpp \ | ||
12 | qcopbridge.cpp \ | ||
13 | oqwsserver.cpp | ||
14 | |||
15 | INCLUDEPATH+= $(OPIEDIR)/include | ||
16 | DEPENDPATH+= $(OPIEDIR)/include . | ||
17 | TARGET = op-qws | ||
18 | LIBS += -lqpe -lopie | ||
19 | |||
20 | include ( $(OPIEDIR)/include.pro ) | ||
diff --git a/core/qws/transferserver.cpp b/core/qws/transferserver.cpp new file mode 100644 index 0000000..0337a94 --- a/dev/null +++ b/core/qws/transferserver.cpp | |||
@@ -0,0 +1,1424 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of the Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | #define _XOPEN_SOURCE | ||
21 | #include <pwd.h> | ||
22 | #include <sys/types.h> | ||
23 | #include <unistd.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <time.h> | ||
26 | #include <shadow.h> | ||
27 | |||
28 | /* we need the _OS_LINUX stuff first ! */ | ||
29 | #include <qglobal.h> | ||
30 | |||
31 | #ifndef _OS_LINUX_ | ||
32 | |||
33 | extern "C" | ||
34 | { | ||
35 | #include <uuid/uuid.h> | ||
36 | #define UUID_H_INCLUDED | ||
37 | } | ||
38 | |||
39 | #endif // not defined linux | ||
40 | |||
41 | #if defined(_OS_LINUX_) | ||
42 | #include <shadow.h> | ||
43 | #endif | ||
44 | |||
45 | #include <qdir.h> | ||
46 | #include <qfile.h> | ||
47 | #include <qtextstream.h> | ||
48 | #include <qdatastream.h> | ||
49 | #include <qmessagebox.h> | ||
50 | #include <qstringlist.h> | ||
51 | #include <qfileinfo.h> | ||
52 | #include <qregexp.h> | ||
53 | //#include <qpe/qcopchannel_qws.h> | ||
54 | #include <qpe/process.h> | ||
55 | #include <qpe/global.h> | ||
56 | #include <qpe/config.h> | ||
57 | #include <qpe/contact.h> | ||
58 | #include <qpe/quuid.h> | ||
59 | #include <qpe/version.h> | ||
60 | #include <qpe/qcopenvelope_qws.h> | ||
61 | |||
62 | #include "transferserver.h" | ||
63 | #include <opie/oprocess.h> | ||
64 | |||
65 | const int block_size = 51200; | ||
66 | |||
67 | TransferServer::TransferServer( Q_UINT16 port, QObject *parent , | ||
68 | const char* name ) | ||
69 | : QServerSocket( port, 1, parent, name ) | ||
70 | { | ||
71 | if ( !ok() ) | ||
72 | qWarning( "Failed to bind to port %d", port ); | ||
73 | } | ||
74 | |||
75 | TransferServer::~TransferServer() | ||
76 | { | ||
77 | } | ||
78 | |||
79 | void TransferServer::newConnection( int socket ) | ||
80 | { | ||
81 | (void) new ServerPI( socket, this ); | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * small class in anonymous namespace | ||
86 | * to generate a QUUid for us | ||
87 | */ | ||
88 | namespace | ||
89 | { | ||
90 | struct UidGen | ||
91 | { | ||
92 | QString uuid(); | ||
93 | }; | ||
94 | #if !defined(_OS_LINUX_) | ||
95 | |||
96 | QString UidGen::uuid() | ||
97 | { | ||
98 | uuid_t uuid; | ||
99 | uuid_generate( uuid ); | ||
100 | return QUUid( uuid ).toString(); | ||
101 | } | ||
102 | #else | ||
103 | /* | ||
104 | * linux got a /proc/sys/kernel/random/uuid file | ||
105 | * it'll generate the uuids for us | ||
106 | */ | ||
107 | QString UidGen::uuid() | ||
108 | { | ||
109 | QFile file( "/proc/sys/kernel/random/uuid" ); | ||
110 | if (!file.open(IO_ReadOnly ) ) | ||
111 | return QString::null; | ||
112 | |||
113 | QTextStream stream(&file); | ||
114 | |||
115 | return "{" + stream.read().stripWhiteSpace() + "}"; | ||
116 | } | ||
117 | #endif | ||
118 | } | ||
119 | |||
120 | QString SyncAuthentication::serverId() | ||
121 | { | ||
122 | Config cfg("Security"); | ||
123 | cfg.setGroup("Sync"); | ||
124 | QString r = cfg.readEntry("serverid"); | ||
125 | if ( r.isEmpty() ) { | ||
126 | UidGen gen; | ||
127 | r = gen.uuid(); | ||
128 | cfg.writeEntry("serverid", r ); | ||
129 | } | ||
130 | return r; | ||
131 | } | ||
132 | |||
133 | QString SyncAuthentication::ownerName() | ||
134 | { | ||
135 | QString vfilename = Global::applicationFileName("addressbook", | ||
136 | "businesscard.vcf"); | ||
137 | if (QFile::exists(vfilename)) { | ||
138 | Contact c; | ||
139 | c = Contact::readVCard( vfilename )[0]; | ||
140 | return c.fullName(); | ||
141 | } | ||
142 | |||
143 | return ""; | ||
144 | } | ||
145 | |||
146 | QString SyncAuthentication::loginName() | ||
147 | { | ||
148 | struct passwd *pw; | ||
149 | pw = getpwuid( geteuid() ); | ||
150 | return QString::fromLocal8Bit( pw->pw_name ); | ||
151 | } | ||
152 | |||
153 | int SyncAuthentication::isAuthorized(QHostAddress peeraddress) | ||
154 | { | ||
155 | Config cfg("Security"); | ||
156 | cfg.setGroup("Sync"); | ||
157 | // QString allowedstr = cfg.readEntry("auth_peer","192.168.1.0"); | ||
158 | uint auth_peer = cfg.readNumEntry("auth_peer", 0xc0a80100); | ||
159 | |||
160 | // QHostAddress allowed; | ||
161 | // allowed.setAddress(allowedstr); | ||
162 | // uint auth_peer = allowed.ip4Addr(); | ||
163 | uint auth_peer_bits = cfg.readNumEntry("auth_peer_bits", 24); | ||
164 | uint mask = auth_peer_bits >= 32 // shifting by 32 is not defined | ||
165 | ? 0xffffffff : (((1 << auth_peer_bits) - 1) << (32 - auth_peer_bits)); | ||
166 | return (peeraddress.ip4Addr() & mask) == auth_peer; | ||
167 | } | ||
168 | |||
169 | bool SyncAuthentication::checkUser( const QString& user ) | ||
170 | { | ||
171 | if ( user.isEmpty() ) | ||
172 | return FALSE; | ||
173 | QString euser = loginName(); | ||
174 | return user == euser; | ||
175 | } | ||
176 | |||
177 | bool SyncAuthentication::checkPassword( const QString& password ) | ||
178 | { | ||
179 | #ifdef ALLOW_UNIX_USER_FTP | ||
180 | // First, check system password... | ||
181 | |||
182 | struct passwd *pw = 0; | ||
183 | struct spwd *spw = 0; | ||
184 | |||
185 | pw = getpwuid( geteuid() ); | ||
186 | spw = getspnam( pw->pw_name ); | ||
187 | |||
188 | QString cpwd = QString::fromLocal8Bit( pw->pw_passwd ); | ||
189 | if ( cpwd == "x" && spw ) | ||
190 | cpwd = QString::fromLocal8Bit( spw->sp_pwdp ); | ||
191 | |||
192 | // Note: some systems use more than crypt for passwords. | ||
193 | QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) ); | ||
194 | if ( cpwd == cpassword ) | ||
195 | return TRUE; | ||
196 | #endif | ||
197 | |||
198 | static int lastdenial = 0; | ||
199 | static int denials = 0; | ||
200 | int now = time(0); | ||
201 | |||
202 | // Detect old Qtopia Desktop (no password) | ||
203 | if ( password.isEmpty() ) { | ||
204 | if ( denials < 1 || now > lastdenial + 600 ) { | ||
205 | QMessageBox::warning( 0, tr("Sync Connection"), | ||
206 | tr("<p>An unauthorized system is requesting access to this device." | ||
207 | "<p>If you are using a version of Qtopia Desktop older than 1.5.1, " | ||
208 | "please upgrade."), | ||
209 | tr("Deny") ); | ||
210 | denials++; | ||
211 | lastdenial = now; | ||
212 | } | ||
213 | return FALSE; | ||
214 | } | ||
215 | |||
216 | // Second, check sync password... | ||
217 | QString pass = password.left(6); | ||
218 | /* old QtopiaDesktops are sending | ||
219 | * rootme newer versions got a Qtopia | ||
220 | * prefixed. Qtopia prefix will suceed | ||
221 | * until the sync software syncs up | ||
222 | * FIXME | ||
223 | */ | ||
224 | if ( pass == "rootme" || pass == "Qtopia") { | ||
225 | |||
226 | QString cpassword = QString::fromLocal8Bit( crypt( password.mid(8).local8Bit(), "qp" ) ); | ||
227 | Config cfg("Security"); | ||
228 | cfg.setGroup("Sync"); | ||
229 | QString pwds = cfg.readEntry("Passwords"); | ||
230 | if ( QStringList::split(QChar(' '), pwds).contains(cpassword) ) | ||
231 | return TRUE; | ||
232 | |||
233 | // Unrecognized system. Be careful... | ||
234 | |||
235 | if ( (denials > 2 && now < lastdenial + 600) | ||
236 | || QMessageBox::warning(0, tr("Sync Connection"), | ||
237 | tr("<p>An unrecognized system is requesting access to this device." | ||
238 | "<p>If you have just initiated a Sync for the first time, this is normal."), | ||
239 | tr("Allow"), tr("Deny"), 0, 1, 1 ) == 1 ) { | ||
240 | denials++; | ||
241 | lastdenial = now; | ||
242 | return FALSE; | ||
243 | } | ||
244 | else { | ||
245 | denials = 0; | ||
246 | cfg.writeEntry("Passwords", pwds + " " + cpassword); | ||
247 | return TRUE; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | return FALSE; | ||
252 | } | ||
253 | |||
254 | ServerPI::ServerPI( int socket, QObject *parent , const char* name ) | ||
255 | : QSocket( parent, name ) , dtp( 0 ), serversocket( 0 ), waitsocket( 0 ) | ||
256 | { | ||
257 | state = Connected; | ||
258 | |||
259 | setSocket( socket ); | ||
260 | |||
261 | peerport = peerPort(); | ||
262 | peeraddress = peerAddress(); | ||
263 | |||
264 | #ifndef INSECURE | ||
265 | |||
266 | if ( !SyncAuthentication::isAuthorized(peeraddress) ) { | ||
267 | state = Forbidden; | ||
268 | startTimer( 0 ); | ||
269 | } | ||
270 | else | ||
271 | #endif | ||
272 | { | ||
273 | connect( this, SIGNAL( readyRead() ), SLOT( read() ) ); | ||
274 | connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); | ||
275 | |||
276 | passiv = FALSE; | ||
277 | for ( int i = 0; i < 4; i++ ) | ||
278 | wait[i] = FALSE; | ||
279 | |||
280 | send( "220 Qtopia " QPE_VERSION " FTP Server" ); | ||
281 | state = Wait_USER; | ||
282 | |||
283 | dtp = new ServerDTP( this ); | ||
284 | connect( dtp, SIGNAL( completed() ), SLOT( dtpCompleted() ) ); | ||
285 | connect( dtp, SIGNAL( failed() ), SLOT( dtpFailed() ) ); | ||
286 | connect( dtp, SIGNAL( error( int ) ), SLOT( dtpError( int ) ) ); | ||
287 | |||
288 | |||
289 | directory = QDir::currentDirPath(); | ||
290 | |||
291 | static int p = 1024; | ||
292 | |||
293 | while ( !serversocket || !serversocket->ok() ) { | ||
294 | delete serversocket; | ||
295 | serversocket = new ServerSocket( ++p, this ); | ||
296 | } | ||
297 | connect( serversocket, SIGNAL( newIncomming( int ) ), | ||
298 | SLOT( newConnection( int ) ) ); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | ServerPI::~ServerPI() | ||
303 | { | ||
304 | } | ||
305 | |||
306 | void ServerPI::connectionClosed() | ||
307 | { | ||
308 | // qDebug( "Debug: Connection closed" ); | ||
309 | delete this; | ||
310 | } | ||
311 | |||
312 | void ServerPI::send( const QString& msg ) | ||
313 | { | ||
314 | QTextStream os( this ); | ||
315 | os << msg << endl; | ||
316 | //qDebug( "Reply: %s", msg.latin1() ); | ||
317 | } | ||
318 | |||
319 | void ServerPI::read() | ||
320 | { | ||
321 | while ( canReadLine() ) | ||
322 | process( readLine().stripWhiteSpace() ); | ||
323 | } | ||
324 | |||
325 | bool ServerPI::checkReadFile( const QString& file ) | ||
326 | { | ||
327 | QString filename; | ||
328 | |||
329 | if ( file[0] != "/" ) | ||
330 | filename = directory.path() + "/" + file; | ||
331 | else | ||
332 | filename = file; | ||
333 | |||
334 | QFileInfo fi( filename ); | ||
335 | return ( fi.exists() && fi.isReadable() ); | ||
336 | } | ||
337 | |||
338 | bool ServerPI::checkWriteFile( const QString& file ) | ||
339 | { | ||
340 | QString filename; | ||
341 | |||
342 | if ( file[0] != "/" ) | ||
343 | filename = directory.path() + "/" + file; | ||
344 | else | ||
345 | filename = file; | ||
346 | |||
347 | QFileInfo fi( filename ); | ||
348 | |||
349 | if ( fi.exists() ) | ||
350 | if ( !QFile( filename ).remove() ) | ||
351 | return FALSE; | ||
352 | return TRUE; | ||
353 | } | ||
354 | |||
355 | void ServerPI::process( const QString& message ) | ||
356 | { | ||
357 | //qDebug( "Command: %s", message.latin1() ); | ||
358 | |||
359 | // split message using "," as separator | ||
360 | QStringList msg = QStringList::split( " ", message ); | ||
361 | if ( msg.isEmpty() ) | ||
362 | return ; | ||
363 | |||
364 | // command token | ||
365 | QString cmd = msg[0].upper(); | ||
366 | |||
367 | // argument token | ||
368 | QString arg; | ||
369 | if ( msg.count() >= 2 ) | ||
370 | arg = msg[1]; | ||
371 | |||
372 | // full argument string | ||
373 | QString args; | ||
374 | if ( msg.count() >= 2 ) { | ||
375 | QStringList copy( msg ); | ||
376 | // FIXME: for Qt3 | ||
377 | // copy.pop_front() | ||
378 | copy.remove( copy.begin() ); | ||
379 | args = copy.join( " " ); | ||
380 | } | ||
381 | |||
382 | //qDebug( "args: %s", args.latin1() ); | ||
383 | |||
384 | // we always respond to QUIT, regardless of state | ||
385 | if ( cmd == "QUIT" ) { | ||
386 | send( "211 Good bye!" ); | ||
387 | delete this; | ||
388 | return ; | ||
389 | } | ||
390 | |||
391 | // connected to client | ||
392 | if ( Connected == state ) | ||
393 | return ; | ||
394 | |||
395 | // waiting for user name | ||
396 | if ( Wait_USER == state ) { | ||
397 | |||
398 | if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) { | ||
399 | send( "530 Please login with USER and PASS" ); | ||
400 | return ; | ||
401 | } | ||
402 | send( "331 User name ok, need password" ); | ||
403 | state = Wait_PASS; | ||
404 | return ; | ||
405 | } | ||
406 | |||
407 | // waiting for password | ||
408 | if ( Wait_PASS == state ) { | ||
409 | |||
410 | if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) { | ||
411 | send( "530 Please login with USER and PASS" ); | ||
412 | return ; | ||
413 | } | ||
414 | send( "230 User logged in, proceed" ); | ||
415 | state = Ready; | ||
416 | return ; | ||
417 | } | ||
418 | |||
419 | // ACCESS CONTROL COMMANDS | ||
420 | |||
421 | |||
422 | // account (ACCT) | ||
423 | if ( cmd == "ACCT" ) { | ||
424 | // even wu-ftp does not support it | ||
425 | send( "502 Command not implemented" ); | ||
426 | } | ||
427 | |||
428 | // change working directory (CWD) | ||
429 | else if ( cmd == "CWD" ) { | ||
430 | |||
431 | if ( !args.isEmpty() ) { | ||
432 | if ( directory.cd( args, TRUE ) ) | ||
433 | send( "250 Requested file action okay, completed" ); | ||
434 | else | ||
435 | send( "550 Requested action not taken" ); | ||
436 | } | ||
437 | else | ||
438 | send( "500 Syntax error, command unrecognized" ); | ||
439 | } | ||
440 | |||
441 | // change to parent directory (CDUP) | ||
442 | else if ( cmd == "CDUP" ) { | ||
443 | if ( directory.cdUp() ) | ||
444 | send( "250 Requested file action okay, completed" ); | ||
445 | else | ||
446 | send( "550 Requested action not taken" ); | ||
447 | } | ||
448 | |||
449 | // structure mount (SMNT) | ||
450 | else if ( cmd == "SMNT" ) { | ||
451 | // even wu-ftp does not support it | ||
452 | send( "502 Command not implemented" ); | ||
453 | } | ||
454 | |||
455 | // reinitialize (REIN) | ||
456 | else if ( cmd == "REIN" ) { | ||
457 | // even wu-ftp does not support it | ||
458 | send( "502 Command not implemented" ); | ||
459 | } | ||
460 | |||
461 | |||
462 | // TRANSFER PARAMETER COMMANDS | ||
463 | |||
464 | |||
465 | // data port (PORT) | ||
466 | else if ( cmd == "PORT" ) { | ||
467 | if ( parsePort( arg ) ) | ||
468 | send( "200 Command okay" ); | ||
469 | else | ||
470 | send( "500 Syntax error, command unrecognized" ); | ||
471 | } | ||
472 | |||
473 | // passive (PASV) | ||
474 | else if ( cmd == "PASV" ) { | ||
475 | passiv = TRUE; | ||
476 | send( "227 Entering Passive Mode (" | ||
477 | + address().toString().replace( QRegExp( "\\." ), "," ) + "," | ||
478 | + QString::number( ( serversocket->port() ) >> 8 ) + "," | ||
479 | + QString::number( ( serversocket->port() ) & 0xFF ) + ")" ); | ||
480 | } | ||
481 | |||
482 | // representation type (TYPE) | ||
483 | else if ( cmd == "TYPE" ) { | ||
484 | if ( arg.upper() == "A" || arg.upper() == "I" ) | ||
485 | send( "200 Command okay" ); | ||
486 | else | ||
487 | send( "504 Command not implemented for that parameter" ); | ||
488 | } | ||
489 | |||
490 | // file structure (STRU) | ||
491 | else if ( cmd == "STRU" ) { | ||
492 | if ( arg.upper() == "F" ) | ||
493 | send( "200 Command okay" ); | ||
494 | else | ||
495 | send( "504 Command not implemented for that parameter" ); | ||
496 | } | ||
497 | |||
498 | // transfer mode (MODE) | ||
499 | else if ( cmd == "MODE" ) { | ||
500 | if ( arg.upper() == "S" ) | ||
501 | send( "200 Command okay" ); | ||
502 | else | ||
503 | send( "504 Command not implemented for that parameter" ); | ||
504 | } | ||
505 | |||
506 | |||
507 | // FTP SERVICE COMMANDS | ||
508 | |||
509 | |||
510 | // retrieve (RETR) | ||
511 | else if ( cmd == "RETR" ) | ||
512 | if ( !args.isEmpty() && checkReadFile( absFilePath( args ) ) | ||
513 | || backupRestoreGzip( absFilePath( args ) ) ) { | ||
514 | send( "150 File status okay" ); | ||
515 | sendFile( absFilePath( args ) ); | ||
516 | } | ||
517 | else { | ||
518 | qDebug("550 Requested action not taken"); | ||
519 | send( "550 Requested action not taken" ); | ||
520 | } | ||
521 | |||
522 | // store (STOR) | ||
523 | else if ( cmd == "STOR" ) | ||
524 | if ( !args.isEmpty() && checkWriteFile( absFilePath( args ) ) ) { | ||
525 | send( "150 File status okay" ); | ||
526 | retrieveFile( absFilePath( args ) ); | ||
527 | } | ||
528 | else | ||
529 | send( "550 Requested action not taken" ); | ||
530 | |||
531 | // store unique (STOU) | ||
532 | else if ( cmd == "STOU" ) { | ||
533 | send( "502 Command not implemented" ); | ||
534 | } | ||
535 | |||
536 | // append (APPE) | ||
537 | else if ( cmd == "APPE" ) { | ||
538 | send( "502 Command not implemented" ); | ||
539 | } | ||
540 | |||
541 | // allocate (ALLO) | ||
542 | else if ( cmd == "ALLO" ) { | ||
543 | send( "200 Command okay" ); | ||
544 | } | ||
545 | |||
546 | // restart (REST) | ||
547 | else if ( cmd == "REST" ) { | ||
548 | send( "502 Command not implemented" ); | ||
549 | } | ||
550 | |||
551 | // rename from (RNFR) | ||
552 | else if ( cmd == "RNFR" ) { | ||
553 | renameFrom = QString::null; | ||
554 | if ( args.isEmpty() ) | ||
555 | send( "500 Syntax error, command unrecognized" ); | ||
556 | else { | ||
557 | QFile file( absFilePath( args ) ); | ||
558 | if ( file.exists() ) { | ||
559 | send( "350 File exists, ready for destination name" ); | ||
560 | renameFrom = absFilePath( args ); | ||
561 | } | ||
562 | else | ||
563 | send( "550 Requested action not taken" ); | ||
564 | } | ||
565 | } | ||
566 | |||
567 | // rename to (RNTO) | ||
568 | else if ( cmd == "RNTO" ) { | ||
569 | if ( lastCommand != "RNFR" ) | ||
570 | send( "503 Bad sequence of commands" ); | ||
571 | else if ( args.isEmpty() ) | ||
572 | send( "500 Syntax error, command unrecognized" ); | ||
573 | else { | ||
574 | QDir dir( absFilePath( args ) ); | ||
575 | if ( dir.rename( renameFrom, absFilePath( args ), TRUE ) ) | ||
576 | send( "250 Requested file action okay, completed." ); | ||
577 | else | ||
578 | send( "550 Requested action not taken" ); | ||
579 | } | ||
580 | } | ||
581 | |||
582 | // abort (ABOR) | ||
583 | else if ( cmd.contains( "ABOR" ) ) { | ||
584 | dtp->close(); | ||
585 | if ( dtp->dtpMode() != ServerDTP::Idle ) | ||
586 | send( "426 Connection closed; transfer aborted" ); | ||
587 | else | ||
588 | send( "226 Closing data connection" ); | ||
589 | } | ||
590 | |||
591 | // delete (DELE) | ||
592 | else if ( cmd == "DELE" ) { | ||
593 | if ( args.isEmpty() ) | ||
594 | send( "500 Syntax error, command unrecognized" ); | ||
595 | else { | ||
596 | QFile file( absFilePath( args ) ) ; | ||
597 | if ( file.remove() ) { | ||
598 | send( "250 Requested file action okay, completed" ); | ||
599 | QCopEnvelope e("QPE/System", "linkChanged(QString)" ); | ||
600 | e << file.name(); | ||
601 | } | ||
602 | else { | ||
603 | send( "550 Requested action not taken" ); | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | |||
608 | // remove directory (RMD) | ||
609 | else if ( cmd == "RMD" ) { | ||
610 | if ( args.isEmpty() ) | ||
611 | send( "500 Syntax error, command unrecognized" ); | ||
612 | else { | ||
613 | QDir dir; | ||
614 | if ( dir.rmdir( absFilePath( args ), TRUE ) ) | ||
615 | send( "250 Requested file action okay, completed" ); | ||
616 | else | ||
617 | send( "550 Requested action not taken" ); | ||
618 | } | ||
619 | } | ||
620 | |||
621 | // make directory (MKD) | ||
622 | else if ( cmd == "MKD" ) { | ||
623 | if ( args.isEmpty() ) { | ||
624 | qDebug(" Error: no arg"); | ||
625 | send( "500 Syntax error, command unrecognized" ); | ||
626 | } | ||
627 | else { | ||
628 | QDir dir; | ||
629 | if ( dir.mkdir( absFilePath( args ), TRUE ) ) | ||
630 | send( "250 Requested file action okay, completed." ); | ||
631 | else | ||
632 | send( "550 Requested action not taken" ); | ||
633 | } | ||
634 | } | ||
635 | |||
636 | // print working directory (PWD) | ||
637 | else if ( cmd == "PWD" ) { | ||
638 | send( "257 \"" + directory.path() + "\"" ); | ||
639 | } | ||
640 | |||
641 | // list (LIST) | ||
642 | else if ( cmd == "LIST" ) { | ||
643 | if ( sendList( absFilePath( args ) ) ) | ||
644 | send( "150 File status okay" ); | ||
645 | else | ||
646 | send( "500 Syntax error, command unrecognized" ); | ||
647 | } | ||
648 | |||
649 | // size (SIZE) | ||
650 | else if ( cmd == "SIZE" ) { | ||
651 | QString filePath = absFilePath( args ); | ||
652 | QFileInfo fi( filePath ); | ||
653 | bool gzipfile = backupRestoreGzip( filePath ); | ||
654 | if ( !fi.exists() && !gzipfile ) | ||
655 | send( "500 Syntax error, command unrecognized" ); | ||
656 | else { | ||
657 | if ( !gzipfile ) | ||
658 | send( "213 " + QString::number( fi.size() ) ); | ||
659 | else { | ||
660 | Process duproc( QString("du") ); | ||
661 | duproc.addArgument("-s"); | ||
662 | QString in, out; | ||
663 | if ( !duproc.exec(in, out) ) { | ||
664 | qDebug("du process failed; just sending back 1K"); | ||
665 | send( "213 1024"); | ||
666 | } | ||
667 | else { | ||
668 | QString size = out.left( out.find("\t") ); | ||
669 | int guess = size.toInt() / 5; | ||
670 | if ( filePath.contains("doc") ) | ||
671 | guess *= 1000; | ||
672 | qDebug("sending back gzip guess of %d", guess); | ||
673 | send( "213 " + QString::number(guess) ); | ||
674 | } | ||
675 | } | ||
676 | } | ||
677 | } | ||
678 | // name list (NLST) | ||
679 | else if ( cmd == "NLST" ) { | ||
680 | send( "502 Command not implemented" ); | ||
681 | } | ||
682 | |||
683 | // site parameters (SITE) | ||
684 | else if ( cmd == "SITE" ) { | ||
685 | send( "502 Command not implemented" ); | ||
686 | } | ||
687 | |||
688 | // system (SYST) | ||
689 | else if ( cmd == "SYST" ) { | ||
690 | send( "215 UNIX Type: L8" ); | ||
691 | } | ||
692 | |||
693 | // status (STAT) | ||
694 | else if ( cmd == "STAT" ) { | ||
695 | send( "502 Command not implemented" ); | ||
696 | } | ||
697 | |||
698 | // help (HELP ) | ||
699 | else if ( cmd == "HELP" ) { | ||
700 | send( "502 Command not implemented" ); | ||
701 | } | ||
702 | |||
703 | // noop (NOOP) | ||
704 | else if ( cmd == "NOOP" ) { | ||
705 | send( "200 Command okay" ); | ||
706 | } | ||
707 | |||
708 | // not implemented | ||
709 | else | ||
710 | send( "502 Command not implemented" ); | ||
711 | |||
712 | lastCommand = cmd; | ||
713 | } | ||
714 | |||
715 | bool ServerPI::backupRestoreGzip( const QString &file ) | ||
716 | { | ||
717 | return (file.find( "backup" ) != -1 && | ||
718 | file.findRev( ".tgz" ) == (int)file.length() - 4 ); | ||
719 | } | ||
720 | |||
721 | bool ServerPI::backupRestoreGzip( const QString &file, QStringList &targets ) | ||
722 | { | ||
723 | if ( file.find( "backup" ) != -1 && | ||
724 | file.findRev( ".tgz" ) == (int)file.length() - 4 ) { | ||
725 | QFileInfo info( file ); | ||
726 | targets = info.dirPath( TRUE ); | ||
727 | qDebug("ServerPI::backupRestoreGzip for %s = %s", file.latin1(), | ||
728 | targets.join(" ").latin1() ); | ||
729 | return true; | ||
730 | } | ||
731 | return false; | ||
732 | } | ||
733 | |||
734 | void ServerPI::sendFile( const QString& file ) | ||
735 | { | ||
736 | if ( passiv ) { | ||
737 | wait[SendFile] = TRUE; | ||
738 | waitfile = file; | ||
739 | if ( waitsocket ) | ||
740 | newConnection( waitsocket ); | ||
741 | } | ||
742 | else { | ||
743 | QStringList targets; | ||
744 | if ( backupRestoreGzip( file, targets ) ) | ||
745 | dtp->sendGzipFile( file, targets, peeraddress, peerport ); | ||
746 | else | ||
747 | dtp->sendFile( file, peeraddress, peerport ); | ||
748 | } | ||
749 | } | ||
750 | |||
751 | void ServerPI::retrieveFile( const QString& file ) | ||
752 | { | ||
753 | if ( passiv ) { | ||
754 | wait[RetrieveFile] = TRUE; | ||
755 | waitfile = file; | ||
756 | if ( waitsocket ) | ||
757 | newConnection( waitsocket ); | ||
758 | } | ||
759 | else { | ||
760 | QStringList targets; | ||
761 | if ( backupRestoreGzip( file, targets ) ) | ||
762 | dtp->retrieveGzipFile( file, peeraddress, peerport ); | ||
763 | else | ||
764 | dtp->retrieveFile( file, peeraddress, peerport ); | ||
765 | } | ||
766 | } | ||
767 | |||
768 | bool ServerPI::parsePort( const QString& pp ) | ||
769 | { | ||
770 | QStringList p = QStringList::split( ",", pp ); | ||
771 | if ( p.count() != 6 ) | ||
772 | return FALSE; | ||
773 | |||
774 | // h1,h2,h3,h4,p1,p2 | ||
775 | peeraddress = QHostAddress( ( p[0].toInt() << 24 ) + ( p[1].toInt() << 16 ) + | ||
776 | ( p[2].toInt() << 8 ) + p[3].toInt() ); | ||
777 | peerport = ( p[4].toInt() << 8 ) + p[5].toInt(); | ||
778 | return TRUE; | ||
779 | } | ||
780 | |||
781 | void ServerPI::dtpCompleted() | ||
782 | { | ||
783 | send( "226 Closing data connection, file transfer successful" ); | ||
784 | if ( dtp->dtpMode() == ServerDTP::RetrieveFile ) { | ||
785 | QString fn = dtp->fileName(); | ||
786 | if ( fn.right(8) == ".desktop" && fn.find("/Documents/") >= 0 ) { | ||
787 | QCopEnvelope e("QPE/System", "linkChanged(QString)" ); | ||
788 | e << fn; | ||
789 | } | ||
790 | } | ||
791 | waitsocket = 0; | ||
792 | dtp->close(); | ||
793 | } | ||
794 | |||
795 | void ServerPI::dtpFailed() | ||
796 | { | ||
797 | dtp->close(); | ||
798 | waitsocket = 0; | ||
799 | send( "451 Requested action aborted: local error in processing" ); | ||
800 | } | ||
801 | |||
802 | void ServerPI::dtpError( int ) | ||
803 | { | ||
804 | dtp->close(); | ||
805 | waitsocket = 0; | ||
806 | send( "451 Requested action aborted: local error in processing" ); | ||
807 | } | ||
808 | |||
809 | bool ServerPI::sendList( const QString& arg ) | ||
810 | { | ||
811 | QByteArray listing; | ||
812 | QBuffer buffer( listing ); | ||
813 | |||
814 | if ( !buffer.open( IO_WriteOnly ) ) | ||
815 | return FALSE; | ||
816 | |||
817 | QTextStream ts( &buffer ); | ||
818 | QString fn = arg; | ||
819 | |||
820 | if ( fn.isEmpty() ) | ||
821 | fn = directory.path(); | ||
822 | |||
823 | QFileInfo fi( fn ); | ||
824 | if ( !fi.exists() ) | ||
825 | return FALSE; | ||
826 | |||
827 | // return file listing | ||
828 | if ( fi.isFile() ) { | ||
829 | ts << fileListing( &fi ) << endl; | ||
830 | } | ||
831 | |||
832 | // return directory listing | ||
833 | else if ( fi.isDir() ) { | ||
834 | QDir dir( fn ); | ||
835 | const QFileInfoList *list = dir.entryInfoList( QDir::All | QDir::Hidden ); | ||
836 | |||
837 | QFileInfoListIterator it( *list ); | ||
838 | QFileInfo *info; | ||
839 | |||
840 | unsigned long total = 0; | ||
841 | while ( ( info = it.current() ) ) { | ||
842 | if ( info->fileName() != "." && info->fileName() != ".." ) | ||
843 | total += info->size(); | ||
844 | ++it; | ||
845 | } | ||
846 | |||
847 | ts << "total " << QString::number( total / 1024 ) << endl; | ||
848 | |||
849 | it.toFirst(); | ||
850 | while ( ( info = it.current() ) ) { | ||
851 | if ( info->fileName() == "." || info->fileName() == ".." ) { | ||
852 | ++it; | ||
853 | continue; | ||
854 | } | ||
855 | ts << fileListing( info ) << endl; | ||
856 | ++it; | ||
857 | } | ||
858 | } | ||
859 | |||
860 | if ( passiv ) { | ||
861 | waitarray = buffer.buffer(); | ||
862 | wait[SendByteArray] = TRUE; | ||
863 | if ( waitsocket ) | ||
864 | newConnection( waitsocket ); | ||
865 | } | ||
866 | else | ||
867 | dtp->sendByteArray( buffer.buffer(), peeraddress, peerport ); | ||
868 | return TRUE; | ||
869 | } | ||
870 | |||
871 | QString ServerPI::fileListing( QFileInfo *info ) | ||
872 | { | ||
873 | if ( !info ) | ||
874 | return QString::null; | ||
875 | QString s; | ||
876 | |||
877 | // type char | ||
878 | if ( info->isDir() ) | ||
879 | s += "d"; | ||
880 | else if ( info->isSymLink() ) | ||
881 | s += "l"; | ||
882 | else | ||
883 | s += "-"; | ||
884 | |||
885 | // permisson string | ||
886 | s += permissionString( info ) + " "; | ||
887 | |||
888 | // number of hardlinks | ||
889 | int subdirs = 1; | ||
890 | |||
891 | if ( info->isDir() ) | ||
892 | subdirs = 2; | ||
893 | // FIXME : this is to slow | ||
894 | //if ( info->isDir() ) | ||
895 | //subdirs = QDir( info->absFilePath() ).entryList( QDir::Dirs ).count(); | ||
896 | |||
897 | s += QString::number( subdirs ).rightJustify( 3, ' ', TRUE ) + " "; | ||
898 | |||
899 | // owner | ||
900 | s += info->owner().leftJustify( 8, ' ', TRUE ) + " "; | ||
901 | |||
902 | // group | ||
903 | s += info->group().leftJustify( 8, ' ', TRUE ) + " "; | ||
904 | |||
905 | // file size in bytes | ||
906 | s += QString::number( info->size() ).rightJustify( 9, ' ', TRUE ) + " "; | ||
907 | |||
908 | // last modified date | ||
909 | QDate date = info->lastModified().date(); | ||
910 | QTime time = info->lastModified().time(); | ||
911 | s += date.monthName( date.month() ) + " " | ||
912 | + QString::number( date.day() ).rightJustify( 2, ' ', TRUE ) + " " | ||
913 | + QString::number( time.hour() ).rightJustify( 2, '0', TRUE ) + ":" | ||
914 | + QString::number( time.minute() ).rightJustify( 2, '0', TRUE ) + " "; | ||
915 | |||
916 | // file name | ||
917 | s += info->fileName(); | ||
918 | |||
919 | return s; | ||
920 | } | ||
921 | |||
922 | QString ServerPI::permissionString( QFileInfo *info ) | ||
923 | { | ||
924 | if ( !info ) | ||
925 | return QString( "---------" ); | ||
926 | QString s; | ||
927 | |||
928 | // user | ||
929 | if ( info->permission( QFileInfo::ReadUser ) ) | ||
930 | s += "r"; | ||
931 | else | ||
932 | s += "-"; | ||
933 | if ( info->permission( QFileInfo::WriteUser ) ) | ||
934 | s += "w"; | ||
935 | else | ||
936 | s += "-"; | ||
937 | if ( info->permission( QFileInfo::ExeUser ) ) | ||
938 | s += "x"; | ||
939 | else | ||
940 | s += "-"; | ||
941 | |||
942 | // group | ||
943 | if ( info->permission( QFileInfo::ReadGroup ) ) | ||
944 | s += "r"; | ||
945 | else | ||
946 | s += "-"; | ||
947 | if ( info->permission( QFileInfo::WriteGroup ) ) | ||
948 | s += "w"; | ||
949 | else | ||
950 | s += "-"; | ||
951 | if ( info->permission( QFileInfo::ExeGroup ) ) | ||
952 | s += "x"; | ||
953 | else | ||
954 | s += "-"; | ||
955 | |||
956 | // exec | ||
957 | if ( info->permission( QFileInfo::ReadOther ) ) | ||
958 | s += "r"; | ||
959 | else | ||
960 | s += "-"; | ||
961 | if ( info->permission( QFileInfo::WriteOther ) ) | ||
962 | s += "w"; | ||
963 | else | ||
964 | s += "-"; | ||
965 | if ( info->permission( QFileInfo::ExeOther ) ) | ||
966 | s += "x"; | ||
967 | else | ||
968 | s += "-"; | ||
969 | |||
970 | return s; | ||
971 | } | ||
972 | |||
973 | void ServerPI::newConnection( int socket ) | ||
974 | { | ||
975 | //qDebug( "New incomming connection" ); | ||
976 | |||
977 | if ( !passiv ) | ||
978 | return ; | ||
979 | |||
980 | if ( wait[SendFile] ) { | ||
981 | QStringList targets; | ||
982 | if ( backupRestoreGzip( waitfile, targets ) ) | ||
983 | dtp->sendGzipFile( waitfile, targets ); | ||
984 | else | ||
985 | dtp->sendFile( waitfile ); | ||
986 | dtp->setSocket( socket ); | ||
987 | } | ||
988 | else if ( wait[RetrieveFile] ) { | ||
989 | qDebug("check retrieve file"); | ||
990 | if ( backupRestoreGzip( waitfile ) ) | ||
991 | dtp->retrieveGzipFile( waitfile ); | ||
992 | else | ||
993 | dtp->retrieveFile( waitfile ); | ||
994 | dtp->setSocket( socket ); | ||
995 | } | ||
996 | else if ( wait[SendByteArray] ) { | ||
997 | dtp->sendByteArray( waitarray ); | ||
998 | dtp->setSocket( socket ); | ||
999 | } | ||
1000 | else if ( wait[RetrieveByteArray] ) { | ||
1001 | qDebug("retrieve byte array"); | ||
1002 | dtp->retrieveByteArray(); | ||
1003 | dtp->setSocket( socket ); | ||
1004 | } | ||
1005 | else | ||
1006 | waitsocket = socket; | ||
1007 | |||
1008 | for ( int i = 0; i < 4; i++ ) | ||
1009 | wait[i] = FALSE; | ||
1010 | } | ||
1011 | |||
1012 | QString ServerPI::absFilePath( const QString& file ) | ||
1013 | { | ||
1014 | if ( file.isEmpty() ) | ||
1015 | return file; | ||
1016 | |||
1017 | QString filepath( file ); | ||
1018 | if ( file[0] != "/" ) | ||
1019 | filepath = directory.path() + "/" + file; | ||
1020 | |||
1021 | return filepath; | ||
1022 | } | ||
1023 | |||
1024 | |||
1025 | void ServerPI::timerEvent( QTimerEvent * ) | ||
1026 | { | ||
1027 | connectionClosed(); | ||
1028 | } | ||
1029 | |||
1030 | |||
1031 | ServerDTP::ServerDTP( QObject *parent, const char* name) | ||
1032 | : QSocket( parent, name ), mode( Idle ), createTargzProc( 0 ), | ||
1033 | retrieveTargzProc( 0 ), gzipProc( 0 ) | ||
1034 | { | ||
1035 | |||
1036 | connect( this, SIGNAL( connected() ), SLOT( connected() ) ); | ||
1037 | connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); | ||
1038 | connect( this, SIGNAL( bytesWritten( int ) ), SLOT( bytesWritten( int ) ) ); | ||
1039 | connect( this, SIGNAL( readyRead() ), SLOT( readyRead() ) ); | ||
1040 | |||
1041 | gzipProc = new OProcess( this, "gzipProc" ); | ||
1042 | |||
1043 | createTargzProc = new OProcess( QString("tar"), this, "createTargzProc"); | ||
1044 | createTargzProc->setWorkingDirectory( QDir::rootDirPath() ); | ||
1045 | connect( createTargzProc, SIGNAL( processExited(OProcess *) ), SLOT( targzDone() ) ); | ||
1046 | |||
1047 | QStringList args = "tar"; | ||
1048 | args += "-xv"; | ||
1049 | retrieveTargzProc = new OProcess( args, this, "retrieveTargzProc" ); | ||
1050 | retrieveTargzProc->setWorkingDirectory( QDir::rootDirPath() ); | ||
1051 | connect( retrieveTargzProc, SIGNAL( processExited(OProcess *) ), | ||
1052 | SIGNAL( completed() ) ); | ||
1053 | connect( retrieveTargzProc, SIGNAL( processExited(OProcess *) ), | ||
1054 | SLOT( extractTarDone() ) ); | ||
1055 | } | ||
1056 | |||
1057 | ServerDTP::~ServerDTP() | ||
1058 | { | ||
1059 | buf.close(); | ||
1060 | file.close(); | ||
1061 | createTargzProc->kill(); | ||
1062 | } | ||
1063 | |||
1064 | void ServerDTP::extractTarDone() | ||
1065 | { | ||
1066 | qDebug("extract done"); | ||
1067 | #ifndef QT_NO_COP | ||
1068 | |||
1069 | QCopEnvelope e( "QPE/Desktop", "restoreDone(QString)" ); | ||
1070 | e << file.name(); | ||
1071 | #endif | ||
1072 | } | ||
1073 | |||
1074 | void ServerDTP::connected() | ||
1075 | { | ||
1076 | // send file mode | ||
1077 | switch ( mode ) { | ||
1078 | case SendFile : | ||
1079 | if ( !file.exists() || !file.open( IO_ReadOnly) ) { | ||
1080 | emit failed(); | ||
1081 | mode = Idle; | ||
1082 | return ; | ||
1083 | } | ||
1084 | |||
1085 | //qDebug( "Debug: Sending file '%s'", file.name().latin1() ); | ||
1086 | |||
1087 | bytes_written = 0; | ||
1088 | if ( file.size() == 0 ) { | ||
1089 | //make sure it doesn't hang on empty files | ||
1090 | file.close(); | ||
1091 | emit completed(); | ||
1092 | mode = Idle; | ||
1093 | } | ||
1094 | else { | ||
1095 | |||
1096 | if ( !file.atEnd() ) { | ||
1097 | QCString s; | ||
1098 | s.resize( block_size ); | ||
1099 | int bytes = file.readBlock( s.data(), block_size ); | ||
1100 | writeBlock( s.data(), bytes ); | ||
1101 | } | ||
1102 | } | ||
1103 | break; | ||
1104 | case SendGzipFile: | ||
1105 | if ( createTargzProc->isRunning() ) { | ||
1106 | // SHOULDN'T GET HERE, BUT DOING A SAFETY CHECK ANYWAY | ||
1107 | qWarning("Previous tar --gzip process is still running; killing it..."); | ||
1108 | createTargzProc->kill(); | ||
1109 | } | ||
1110 | |||
1111 | bytes_written = 0; | ||
1112 | qDebug("==>start send tar process"); | ||
1113 | if ( !createTargzProc->start(OProcess::NotifyOnExit, OProcess::Stdout) ) | ||
1114 | qWarning("Error starting %s or %s", | ||
1115 | createTargzProc->args()[0].data(), | ||
1116 | gzipProc->args()[0].data()); | ||
1117 | break; | ||
1118 | case SendBuffer: | ||
1119 | if ( !buf.open( IO_ReadOnly) ) { | ||
1120 | emit failed(); | ||
1121 | mode = Idle; | ||
1122 | return ; | ||
1123 | } | ||
1124 | |||
1125 | // qDebug( "Debug: Sending byte array" ); | ||
1126 | bytes_written = 0; | ||
1127 | while ( !buf.atEnd() ) | ||
1128 | putch( buf.getch() ); | ||
1129 | buf.close(); | ||
1130 | break; | ||
1131 | case RetrieveFile: | ||
1132 | // retrieve file mode | ||
1133 | if ( file.exists() && !file.remove() ) { | ||
1134 | emit failed(); | ||
1135 | mode = Idle; | ||
1136 | return ; | ||
1137 | } | ||
1138 | |||
1139 | if ( !file.open( IO_WriteOnly) ) { | ||
1140 | emit failed(); | ||
1141 | mode = Idle; | ||
1142 | return ; | ||
1143 | } | ||
1144 | // qDebug( "Debug: Retrieving file %s", file.name().latin1() ); | ||
1145 | break; | ||
1146 | case RetrieveGzipFile: | ||
1147 | qDebug("=-> starting tar process to receive .tgz file"); | ||
1148 | break; | ||
1149 | case RetrieveBuffer: | ||
1150 | // retrieve buffer mode | ||
1151 | if ( !buf.open( IO_WriteOnly) ) { | ||
1152 | emit failed(); | ||
1153 | mode = Idle; | ||
1154 | return ; | ||
1155 | } | ||
1156 | // qDebug( "Debug: Retrieving byte array" ); | ||
1157 | break; | ||
1158 | case Idle: | ||
1159 | qDebug("connection established but mode set to Idle; BUG!"); | ||
1160 | break; | ||
1161 | } | ||
1162 | } | ||
1163 | |||
1164 | void ServerDTP::connectionClosed() | ||
1165 | { | ||
1166 | //qDebug( "Debug: Data connection closed %ld bytes written", bytes_written ); | ||
1167 | |||
1168 | // send file mode | ||
1169 | if ( SendFile == mode ) { | ||
1170 | if ( bytes_written == file.size() ) | ||
1171 | emit completed(); | ||
1172 | else | ||
1173 | emit failed(); | ||
1174 | } | ||
1175 | |||
1176 | // send buffer mode | ||
1177 | else if ( SendBuffer == mode ) { | ||
1178 | if ( bytes_written == buf.size() ) | ||
1179 | emit completed(); | ||
1180 | else | ||
1181 | emit failed(); | ||
1182 | } | ||
1183 | |||
1184 | // retrieve file mode | ||
1185 | else if ( RetrieveFile == mode ) { | ||
1186 | file.close(); | ||
1187 | emit completed(); | ||
1188 | } | ||
1189 | |||
1190 | else if ( RetrieveGzipFile == mode ) { | ||
1191 | qDebug("Done writing ungzip file; closing input"); | ||
1192 | gzipProc->flushStdin(); | ||
1193 | gzipProc->closeStdin(); | ||
1194 | } | ||
1195 | |||
1196 | // retrieve buffer mode | ||
1197 | else if ( RetrieveBuffer == mode ) { | ||
1198 | buf.close(); | ||
1199 | emit completed(); | ||
1200 | } | ||
1201 | |||
1202 | mode = Idle; | ||
1203 | } | ||
1204 | |||
1205 | void ServerDTP::bytesWritten( int bytes ) | ||
1206 | { | ||
1207 | bytes_written += bytes; | ||
1208 | |||
1209 | // send file mode | ||
1210 | if ( SendFile == mode ) { | ||
1211 | |||
1212 | if ( bytes_written == file.size() ) { | ||
1213 | // qDebug( "Debug: Sending complete: %d bytes", file.size() ); | ||
1214 | file.close(); | ||
1215 | emit completed(); | ||
1216 | mode = Idle; | ||
1217 | } | ||
1218 | else if ( !file.atEnd() ) { | ||
1219 | QCString s; | ||
1220 | s.resize( block_size ); | ||
1221 | int bytes = file.readBlock( s.data(), block_size ); | ||
1222 | writeBlock( s.data(), bytes ); | ||
1223 | } | ||
1224 | } | ||
1225 | |||
1226 | // send buffer mode | ||
1227 | if ( SendBuffer == mode ) { | ||
1228 | |||
1229 | if ( bytes_written == buf.size() ) { | ||
1230 | // qDebug( "Debug: Sending complete: %d bytes", buf.size() ); | ||
1231 | emit completed(); | ||
1232 | mode = Idle; | ||
1233 | } | ||
1234 | } | ||
1235 | } | ||
1236 | |||
1237 | void ServerDTP::readyRead() | ||
1238 | { | ||
1239 | // retrieve file mode | ||
1240 | if ( RetrieveFile == mode ) { | ||
1241 | QCString s; | ||
1242 | s.resize( bytesAvailable() ); | ||
1243 | readBlock( s.data(), bytesAvailable() ); | ||
1244 | file.writeBlock( s.data(), s.size() ); | ||
1245 | } | ||
1246 | else if ( RetrieveGzipFile == mode ) { | ||
1247 | if ( !gzipProc->isRunning() ) | ||
1248 | gzipProc->start(OProcess::NotifyOnExit, (OProcess::Communication) ( OProcess::Stdin | OProcess::Stdout )); | ||
1249 | |||
1250 | QByteArray s; | ||
1251 | s.resize( bytesAvailable() ); | ||
1252 | readBlock( s.data(), bytesAvailable() ); | ||
1253 | gzipProc->writeStdin( s.data(), s.size() ); | ||
1254 | qDebug("wrote %d bytes to ungzip ", s.size() ); | ||
1255 | } | ||
1256 | // retrieve buffer mode | ||
1257 | else if ( RetrieveBuffer == mode ) { | ||
1258 | QCString s; | ||
1259 | s.resize( bytesAvailable() ); | ||
1260 | readBlock( s.data(), bytesAvailable() ); | ||
1261 | buf.writeBlock( s.data(), s.size() ); | ||
1262 | } | ||
1263 | } | ||
1264 | |||
1265 | void ServerDTP::writeTargzBlock(OProcess *, char *buffer, int buflen) | ||
1266 | { | ||
1267 | writeBlock( buffer, buflen ); | ||
1268 | qDebug("writeTargzBlock %d", buflen); | ||
1269 | if ( !createTargzProc->isRunning() ) { | ||
1270 | qDebug("tar and gzip done"); | ||
1271 | emit completed(); | ||
1272 | mode = Idle; | ||
1273 | disconnect( gzipProc, SIGNAL( receivedStdout(OProcess *, char *, int ) ), | ||
1274 | this, SLOT( writeTargzBlock(OProcess *, char *, int) ) ); | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | void ServerDTP::targzDone() | ||
1279 | { | ||
1280 | //qDebug("targz done"); | ||
1281 | disconnect( createTargzProc, SIGNAL( receivedStdout(OProcess *, char *, int) ), | ||
1282 | this, SLOT( gzipTarBlock(OProcess *, char *, int) ) ); | ||
1283 | gzipProc->closeStdin(); | ||
1284 | } | ||
1285 | |||
1286 | void ServerDTP::gzipTarBlock(OProcess *, char *buffer, int buflen) | ||
1287 | { | ||
1288 | //qDebug("gzipTarBlock"); | ||
1289 | if ( !gzipProc->isRunning() ) { | ||
1290 | //qDebug("auto start gzip proc"); | ||
1291 | gzipProc->start(OProcess::NotifyOnExit, (OProcess::Communication) ( OProcess::Stdin | OProcess::Stdout )); | ||
1292 | } | ||
1293 | gzipProc->writeStdin( buffer, buflen ); | ||
1294 | } | ||
1295 | |||
1296 | void ServerDTP::sendFile( const QString fn, const QHostAddress& host, Q_UINT16 port ) | ||
1297 | { | ||
1298 | file.setName( fn ); | ||
1299 | mode = SendFile; | ||
1300 | connectToHost( host.toString(), port ); | ||
1301 | } | ||
1302 | |||
1303 | void ServerDTP::sendFile( const QString fn ) | ||
1304 | { | ||
1305 | file.setName( fn ); | ||
1306 | mode = SendFile; | ||
1307 | } | ||
1308 | |||
1309 | void ServerDTP::sendGzipFile( const QString &fn, | ||
1310 | const QStringList &archiveTargets, | ||
1311 | const QHostAddress& host, Q_UINT16 port ) | ||
1312 | { | ||
1313 | sendGzipFile( fn, archiveTargets ); | ||
1314 | connectToHost( host.toString(), port ); | ||
1315 | } | ||
1316 | |||
1317 | void ServerDTP::sendGzipFile( const QString &fn, | ||
1318 | const QStringList &archiveTargets ) | ||
1319 | { | ||
1320 | mode = SendGzipFile; | ||
1321 | file.setName( fn ); | ||
1322 | |||
1323 | QStringList args = "tar"; | ||
1324 | args += "-cv"; | ||
1325 | args += archiveTargets; | ||
1326 | qDebug("sendGzipFile %s", args.join(" ").latin1() ); | ||
1327 | createTargzProc->clearArguments( ); | ||
1328 | *createTargzProc << args; | ||
1329 | connect( createTargzProc, | ||
1330 | SIGNAL( receivedStdout(OProcess *, char *, int) ), SLOT( gzipTarBlock(OProcess *, char *, int) ) ); | ||
1331 | |||
1332 | gzipProc->clearArguments( ); | ||
1333 | *gzipProc << "gzip"; | ||
1334 | connect( gzipProc, SIGNAL( receivedStdout(OProcess *, char *, int) ), | ||
1335 | SLOT( writeTargzBlock(OProcess *, char *, int) ) ); | ||
1336 | } | ||
1337 | |||
1338 | void ServerDTP::gunzipDone() | ||
1339 | { | ||
1340 | qDebug("gunzipDone"); | ||
1341 | disconnect( gzipProc, SIGNAL( processExited() ), | ||
1342 | this, SLOT( gunzipDone() ) ); | ||
1343 | retrieveTargzProc->closeStdin(); | ||
1344 | disconnect( gzipProc, SIGNAL( receivedStdout(OProcess *, char *, int) ), | ||
1345 | this, SLOT( tarExtractBlock(OProcess *, char *, int) ) ); | ||
1346 | } | ||
1347 | |||
1348 | void ServerDTP::tarExtractBlock(OProcess *, char *buffer, int buflen) | ||
1349 | { | ||
1350 | qDebug("tarExtractBlock"); | ||
1351 | if ( !retrieveTargzProc->isRunning() ) { | ||
1352 | qDebug("auto start ungzip proc"); | ||
1353 | if ( !retrieveTargzProc->start(OProcess::NotifyOnExit, OProcess::Stdin) ) | ||
1354 | qWarning(" failed to start tar -x process"); | ||
1355 | } | ||
1356 | retrieveTargzProc->writeStdin( buffer, buflen ); | ||
1357 | } | ||
1358 | |||
1359 | |||
1360 | void ServerDTP::retrieveFile( const QString fn, const QHostAddress& host, Q_UINT16 port ) | ||
1361 | { | ||
1362 | file.setName( fn ); | ||
1363 | mode = RetrieveFile; | ||
1364 | connectToHost( host.toString(), port ); | ||
1365 | } | ||
1366 | |||
1367 | void ServerDTP::retrieveFile( const QString fn ) | ||
1368 | { | ||
1369 | file.setName( fn ); | ||
1370 | mode = RetrieveFile; | ||
1371 | } | ||
1372 | |||
1373 | void ServerDTP::retrieveGzipFile( const QString &fn ) | ||
1374 | { | ||
1375 | qDebug("retrieveGzipFile %s", fn.latin1()); | ||
1376 | file.setName( fn ); | ||
1377 | mode = RetrieveGzipFile; | ||
1378 | |||
1379 | gzipProc->clearArguments(); | ||
1380 | *gzipProc << "gunzip"; | ||
1381 | connect( gzipProc, SIGNAL( readyReadStdout() ), | ||
1382 | SLOT( tarExtractBlock() ) ); | ||
1383 | connect( gzipProc, SIGNAL( processExited() ), | ||
1384 | SLOT( gunzipDone() ) ); | ||
1385 | } | ||
1386 | |||
1387 | void ServerDTP::retrieveGzipFile( const QString &fn, const QHostAddress& host, Q_UINT16 port ) | ||
1388 | { | ||
1389 | retrieveGzipFile( fn ); | ||
1390 | connectToHost( host.toString(), port ); | ||
1391 | } | ||
1392 | |||
1393 | void ServerDTP::sendByteArray( const QByteArray& array, const QHostAddress& host, Q_UINT16 port ) | ||
1394 | { | ||
1395 | buf.setBuffer( array ); | ||
1396 | mode = SendBuffer; | ||
1397 | connectToHost( host.toString(), port ); | ||
1398 | } | ||
1399 | |||
1400 | void ServerDTP::sendByteArray( const QByteArray& array ) | ||
1401 | { | ||
1402 | buf.setBuffer( array ); | ||
1403 | mode = SendBuffer; | ||
1404 | } | ||
1405 | |||
1406 | void ServerDTP::retrieveByteArray( const QHostAddress& host, Q_UINT16 port ) | ||
1407 | { | ||
1408 | buf.setBuffer( QByteArray() ); | ||
1409 | mode = RetrieveBuffer; | ||
1410 | connectToHost( host.toString(), port ); | ||
1411 | } | ||
1412 | |||
1413 | void ServerDTP::retrieveByteArray() | ||
1414 | { | ||
1415 | buf.setBuffer( QByteArray() ); | ||
1416 | mode = RetrieveBuffer; | ||
1417 | } | ||
1418 | |||
1419 | void ServerDTP::setSocket( int socket ) | ||
1420 | { | ||
1421 | QSocket::setSocket( socket ); | ||
1422 | connected(); | ||
1423 | } | ||
1424 | |||
diff --git a/core/qws/transferserver.h b/core/qws/transferserver.h new file mode 100644 index 0000000..1c5ab4b --- a/dev/null +++ b/core/qws/transferserver.h | |||
@@ -0,0 +1,179 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of the Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | #include <qserversocket.h> | ||
21 | #include <qsocket.h> | ||
22 | #include <qdir.h> | ||
23 | #include <qfile.h> | ||
24 | #include <qbuffer.h> | ||
25 | |||
26 | class QFileInfo; | ||
27 | class OProcess; | ||
28 | class TransferServer : public QServerSocket | ||
29 | { | ||
30 | Q_OBJECT | ||
31 | |||
32 | public: | ||
33 | TransferServer( Q_UINT16 port, QObject *parent = 0, const char* name = 0 ); | ||
34 | virtual ~TransferServer(); | ||
35 | |||
36 | void newConnection( int socket ); | ||
37 | }; | ||
38 | |||
39 | class SyncAuthentication : QObject | ||
40 | { | ||
41 | Q_OBJECT | ||
42 | |||
43 | public: | ||
44 | static int isAuthorized(QHostAddress peeraddress); | ||
45 | static bool checkPassword(const QString& pw); | ||
46 | static bool checkUser(const QString& user); | ||
47 | |||
48 | static QString serverId(); | ||
49 | static QString loginName(); | ||
50 | static QString ownerName(); | ||
51 | }; | ||
52 | |||
53 | |||
54 | class ServerDTP : public QSocket | ||
55 | { | ||
56 | Q_OBJECT | ||
57 | |||
58 | public: | ||
59 | ServerDTP( QObject *parent = 0, const char* name = 0 ); | ||
60 | ~ServerDTP(); | ||
61 | |||
62 | enum Mode{ Idle = 0, SendFile, SendGzipFile, SendBuffer, | ||
63 | RetrieveFile, RetrieveGzipFile, RetrieveBuffer }; | ||
64 | |||
65 | void sendFile( const QString fn ); | ||
66 | void sendFile( const QString fn, const QHostAddress& host, Q_UINT16 port ); | ||
67 | void sendGzipFile( const QString &fn, const QStringList &archiveTargets ); | ||
68 | void sendGzipFile( const QString &fn, const QStringList &archiveTargets, | ||
69 | const QHostAddress& host, Q_UINT16 port ); | ||
70 | void sendByteArray( const QByteArray& array ); | ||
71 | void sendByteArray( const QByteArray& array, const QHostAddress& host, Q_UINT16 port ); | ||
72 | |||
73 | void retrieveFile( const QString fn ); | ||
74 | void retrieveFile( const QString fn, const QHostAddress& host, Q_UINT16 port ); | ||
75 | void retrieveGzipFile( const QString &fn ); | ||
76 | void retrieveGzipFile( const QString &fn, const QHostAddress& host, Q_UINT16 port ); | ||
77 | void retrieveByteArray(); | ||
78 | void retrieveByteArray( const QHostAddress& host, Q_UINT16 port ); | ||
79 | |||
80 | Mode dtpMode() { return mode; } | ||
81 | QByteArray buffer() { return buf.buffer(); } | ||
82 | QString fileName() const { return file.name(); } | ||
83 | |||
84 | void setSocket( int socket ); | ||
85 | |||
86 | signals: | ||
87 | void completed(); | ||
88 | void failed(); | ||
89 | |||
90 | private slots: | ||
91 | void connectionClosed(); | ||
92 | void connected(); | ||
93 | void bytesWritten( int bytes ); | ||
94 | void readyRead(); | ||
95 | void writeTargzBlock(OProcess *, char *, int); | ||
96 | void targzDone(); | ||
97 | |||
98 | void gzipTarBlock(OProcess *, char *, int); | ||
99 | void tarExtractBlock(OProcess *, char *, int); | ||
100 | void gunzipDone(); | ||
101 | void extractTarDone(); | ||
102 | |||
103 | private: | ||
104 | |||
105 | unsigned long bytes_written; | ||
106 | Mode mode; | ||
107 | QFile file; | ||
108 | QBuffer buf; | ||
109 | OProcess *createTargzProc; | ||
110 | OProcess *retrieveTargzProc; | ||
111 | OProcess *gzipProc; | ||
112 | }; | ||
113 | |||
114 | class ServerSocket : public QServerSocket | ||
115 | { | ||
116 | Q_OBJECT | ||
117 | |||
118 | public: | ||
119 | ServerSocket( Q_UINT16 port, QObject *parent = 0, const char* name = 0 ) | ||
120 | : QServerSocket( port, 1, parent, name ) {} | ||
121 | |||
122 | void newConnection( int socket ) { emit newIncomming( socket ); } | ||
123 | signals: | ||
124 | void newIncomming( int socket ); | ||
125 | }; | ||
126 | |||
127 | class ServerPI : public QSocket | ||
128 | { | ||
129 | Q_OBJECT | ||
130 | |||
131 | enum State { Connected, Wait_USER, Wait_PASS, Ready, Forbidden }; | ||
132 | enum Transfer { SendFile = 0, RetrieveFile = 1, SendByteArray = 2, RetrieveByteArray = 3 }; | ||
133 | |||
134 | public: | ||
135 | ServerPI( int socket, QObject *parent = 0, const char* name = 0 ); | ||
136 | virtual ~ServerPI(); | ||
137 | |||
138 | protected slots: | ||
139 | void read(); | ||
140 | void send( const QString& msg ); | ||
141 | void process( const QString& command ); | ||
142 | void connectionClosed(); | ||
143 | void dtpCompleted(); | ||
144 | void dtpFailed(); | ||
145 | void dtpError( int ); | ||
146 | void newConnection( int socket ); | ||
147 | |||
148 | protected: | ||
149 | bool checkReadFile( const QString& file ); | ||
150 | bool checkWriteFile( const QString& file ); | ||
151 | bool parsePort( const QString& pw ); | ||
152 | bool backupRestoreGzip( const QString &file, QStringList &targets ); | ||
153 | bool backupRestoreGzip( const QString &file ); | ||
154 | |||
155 | bool sendList( const QString& arg ); | ||
156 | void sendFile( const QString& file ); | ||
157 | void retrieveFile( const QString& file ); | ||
158 | |||
159 | QString permissionString( QFileInfo *info ); | ||
160 | QString fileListing( QFileInfo *info ); | ||
161 | QString absFilePath( const QString& file ); | ||
162 | |||
163 | void timerEvent( QTimerEvent *e ); | ||
164 | |||
165 | private: | ||
166 | State state; | ||
167 | Q_UINT16 peerport; | ||
168 | QHostAddress peeraddress; | ||
169 | bool passiv; | ||
170 | bool wait[4]; | ||
171 | ServerDTP *dtp; | ||
172 | ServerSocket *serversocket; | ||
173 | QString waitfile; | ||
174 | QDir directory; | ||
175 | QByteArray waitarray; | ||
176 | QString renameFrom; | ||
177 | QString lastCommand; | ||
178 | int waitsocket; | ||
179 | }; | ||