Diffstat (limited to 'noncore/settings/packagemanager/oipkg.cpp') (more/less context) (show whitespace changes)
-rw-r--r-- | noncore/settings/packagemanager/oipkg.cpp | 505 |
1 files changed, 505 insertions, 0 deletions
diff --git a/noncore/settings/packagemanager/oipkg.cpp b/noncore/settings/packagemanager/oipkg.cpp new file mode 100644 index 0000000..13f3d7d --- a/dev/null +++ b/noncore/settings/packagemanager/oipkg.cpp | |||
@@ -0,0 +1,505 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | |||
4 | Copyright (c) 2003 Dan Williams <drw@handhelds.org> | ||
5 | =. | ||
6 | .=l. | ||
7 | .>+-= | ||
8 | _;:, .> :=|. This program is free software; you can | ||
9 | .> <`_, > . <= redistribute it and/or modify it under | ||
10 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
11 | .="- .-=="i, .._ License as published by the Free Software | ||
12 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
13 | ._= =} : or (at your option) any later version. | ||
14 | .%`+i> _;_. | ||
15 | .i_,=:_. -<s. This program is distributed in the hope that | ||
16 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
17 | : .. .:, . . . without even the implied warranty of | ||
18 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
19 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
20 | ..}^=.= = ; Library General Public License for more | ||
21 | ++= -. .` .: details. | ||
22 | : = ...= . :.=- | ||
23 | -. .:....=;==+<; You should have received a copy of the GNU | ||
24 | -_. . . )=. = Library General Public License along with | ||
25 | -- :-=` this library; see the file COPYING.LIB. | ||
26 | If not, write to the Free Software Foundation, | ||
27 | Inc., 59 Temple Place - Suite 330, | ||
28 | Boston, MA 02111-1307, USA. | ||
29 | |||
30 | */ | ||
31 | |||
32 | #include "oipkg.h" | ||
33 | |||
34 | #include <stdio.h> | ||
35 | |||
36 | #include <qdir.h> | ||
37 | #include <qfile.h> | ||
38 | #include <qtextstream.h> | ||
39 | |||
40 | #include <opie/oprocess.h> | ||
41 | |||
42 | const QString IPKG_EXEC = "ipkg"; // Fully-qualified name of Ipkg executable | ||
43 | const QString IPKG_CONF = "/etc/ipkg.conf"; // Fully-qualified name of Ipkg primary configuration file | ||
44 | const QString IPKG_CONF_DIR = "/etc/ipkg"; // Directory of secondary Ipkg configuration files | ||
45 | const QString IPKG_PKG_PATH = "/usr/lib/ipkg/lists"; // Directory containing server package lists | ||
46 | const QString IPKG_STATUS_PATH = "usr/lib/ipkg/status"; // Destination status file location | ||
47 | |||
48 | OIpkg::OIpkg( Config *config, QObject *parent, const char *name ) | ||
49 | : QObject( parent, name ) | ||
50 | , m_config( config ) | ||
51 | , m_ipkgExec( IPKG_EXEC ) // TODO - find executable? | ||
52 | , m_confInfo( NULL ) | ||
53 | , m_ipkgExecOptions( 0 ) | ||
54 | , m_ipkgExecVerbosity( 1 ) | ||
55 | , m_ipkgProcess( NULL ) | ||
56 | { | ||
57 | } | ||
58 | |||
59 | OIpkg::~OIpkg() | ||
60 | { | ||
61 | // Upon destruction, ensure that items in config list are deleted with list | ||
62 | if ( m_confInfo ) | ||
63 | m_confInfo->setAutoDelete( true ); | ||
64 | |||
65 | // Terminate any running ipkg processes | ||
66 | if ( m_ipkgProcess ) | ||
67 | delete m_ipkgProcess; | ||
68 | } | ||
69 | |||
70 | OConfItemList *OIpkg::configItems() | ||
71 | { | ||
72 | // Retrieve all configuration items | ||
73 | return filterConfItems(); | ||
74 | } | ||
75 | |||
76 | OConfItemList *OIpkg::servers() | ||
77 | { | ||
78 | // Retrieve only servers | ||
79 | return filterConfItems( OConfItem::Source ); | ||
80 | } | ||
81 | |||
82 | OConfItemList *OIpkg::destinations() | ||
83 | { | ||
84 | // Retrieve only destinations | ||
85 | return filterConfItems( OConfItem::Destination ); | ||
86 | } | ||
87 | |||
88 | OConfItemList *OIpkg::options() | ||
89 | { | ||
90 | // Retrieve only destinations | ||
91 | return filterConfItems( OConfItem::Option ); | ||
92 | } | ||
93 | |||
94 | void OIpkg::setConfigItems( OConfItemList *configList ) | ||
95 | { | ||
96 | if ( m_confInfo ) | ||
97 | delete m_confInfo; | ||
98 | |||
99 | m_confInfo = configList; | ||
100 | } | ||
101 | |||
102 | void OIpkg::saveSettings() | ||
103 | { | ||
104 | // Save Ipkg execution options to application configuration file | ||
105 | if ( m_config ) | ||
106 | { | ||
107 | m_config->setGroup( "Ipkg" ); | ||
108 | m_config->writeEntry( "ExecOptions", m_ipkgExecOptions ); | ||
109 | m_config->writeEntry( "Verbosity", m_ipkgExecVerbosity ); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | OPackageList *OIpkg::availablePackages( const QString &server ) | ||
114 | { | ||
115 | // Load Ipkg configuration info if not already cached | ||
116 | if ( !m_confInfo ) | ||
117 | loadConfiguration(); | ||
118 | |||
119 | // Build new server list (caller is responsible for deleting) | ||
120 | OPackageList *pl = new OPackageList; | ||
121 | |||
122 | // Open package list file | ||
123 | QFile f( IPKG_PKG_PATH + "/" + server ); | ||
124 | if ( !f.open( IO_ReadOnly ) ) | ||
125 | return NULL; | ||
126 | QTextStream t( &f ); | ||
127 | |||
128 | // Process all information in package list file | ||
129 | OPackage *package = NULL; | ||
130 | QString line = t.readLine(); | ||
131 | while ( !t.eof() ) | ||
132 | { | ||
133 | // Determine key/value pair | ||
134 | int pos = line.find( ':', 0 ); | ||
135 | QString key; | ||
136 | if ( pos > -1 ) | ||
137 | key = line.mid( 0, pos ); | ||
138 | else | ||
139 | key = QString::null; | ||
140 | QString value = line.mid( pos+2, line.length()-pos ); | ||
141 | |||
142 | // Allocate new package and insert into list | ||
143 | if ( package == NULL && !key.isEmpty() ) | ||
144 | { | ||
145 | package = new OPackage( value ); | ||
146 | package->setSource( server ); | ||
147 | pl->append( package ); | ||
148 | } | ||
149 | |||
150 | // Update package data | ||
151 | if ( key == "Package" ) | ||
152 | package->setName( value ); | ||
153 | else if ( key == "Version" ) | ||
154 | package->setVersion( value ); | ||
155 | else if ( key == "Section" ) | ||
156 | package->setCategory( value ); | ||
157 | //DataManager::setAvailableCategories( value ); | ||
158 | else if ( key.isEmpty() && value.isEmpty() ) | ||
159 | package = NULL; | ||
160 | |||
161 | // Skip past all description lines | ||
162 | if ( key == "Description" ) | ||
163 | { | ||
164 | line = t.readLine(); | ||
165 | while ( !line.isEmpty() && line.find( ':', 0 ) == -1 && !t.eof() ) | ||
166 | line = t.readLine(); | ||
167 | } | ||
168 | else | ||
169 | line = t.readLine(); | ||
170 | } | ||
171 | |||
172 | f.close(); | ||
173 | |||
174 | return pl; | ||
175 | } | ||
176 | |||
177 | OPackageList *OIpkg::installedPackages( const QString &destName, const QString &destPath ) | ||
178 | { | ||
179 | // Load Ipkg configuration info if not already cached | ||
180 | if ( !m_confInfo ) | ||
181 | loadConfiguration(); | ||
182 | |||
183 | // Build new server list (caller is responsible for deleting) | ||
184 | OPackageList *pl = new OPackageList; | ||
185 | |||
186 | // Open status file | ||
187 | QString path = destPath; | ||
188 | if ( path.right( 1 ) != "/" ) | ||
189 | path.append( "/" ); | ||
190 | path.append( IPKG_STATUS_PATH ); | ||
191 | |||
192 | QFile f( path ); | ||
193 | if ( !f.open( IO_ReadOnly ) ) | ||
194 | return NULL; | ||
195 | QTextStream t( &f ); | ||
196 | |||
197 | // Process all information in status file | ||
198 | bool newPackage = false; | ||
199 | QString line = t.readLine(); | ||
200 | QString name; | ||
201 | QString version; | ||
202 | QString status; | ||
203 | |||
204 | while ( !t.eof() ) | ||
205 | { | ||
206 | // Determine key/value pair | ||
207 | int pos = line.find( ':', 0 ); | ||
208 | QString key; | ||
209 | if ( pos > -1 ) | ||
210 | key = line.mid( 0, pos ); | ||
211 | else | ||
212 | key = QString::null; | ||
213 | QString value = line.mid( pos+2, line.length()-pos ); | ||
214 | |||
215 | // Allocate new package and insert into list | ||
216 | if ( newPackage && !key.isEmpty() ) | ||
217 | { | ||
218 | // Add to list only if it has a valid name and is installed | ||
219 | if ( !name.isNull() && status.contains( " installed" ) ) | ||
220 | { | ||
221 | pl->append( new OPackage( name, QString::null, version, QString::null, destName ) ); | ||
222 | name = QString::null; | ||
223 | version = QString::null; | ||
224 | status = QString::null; | ||
225 | |||
226 | newPackage = false; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | // Update package data | ||
231 | if ( key == "Package" ) | ||
232 | name = value; | ||
233 | else if ( key == "Version" ) | ||
234 | version = value; | ||
235 | else if ( key == "Status" ) | ||
236 | status = value; | ||
237 | else if ( key.isEmpty() && value.isEmpty() ) | ||
238 | newPackage = true; | ||
239 | |||
240 | // Skip past all description lines | ||
241 | if ( key == "Description" ) | ||
242 | { | ||
243 | line = t.readLine(); | ||
244 | while ( !line.isEmpty() && line.find( ':', 0 ) == -1 && !t.eof() ) | ||
245 | line = t.readLine(); | ||
246 | } | ||
247 | else | ||
248 | line = t.readLine(); | ||
249 | } | ||
250 | |||
251 | f.close(); | ||
252 | |||
253 | return pl; | ||
254 | } | ||
255 | |||
256 | bool OIpkg::executeCommand( OPackage::Command command, QStringList *parameters, const QString &destination, | ||
257 | const QObject *receiver, const char *slotOutput, const char *slotErrors, | ||
258 | const char *slotFinished, bool rawOutput ) | ||
259 | { | ||
260 | if ( command == OPackage::NotDefined ) | ||
261 | return false; | ||
262 | |||
263 | // Set up command line for execution | ||
264 | QStringList cmdLine; | ||
265 | cmdLine.append( IPKG_EXEC ); | ||
266 | |||
267 | QString verbosity( "-V" ); | ||
268 | verbosity.append( QString::number( m_ipkgExecVerbosity ) ); | ||
269 | cmdLine.append( verbosity ); | ||
270 | |||
271 | // Determine Ipkg execution options | ||
272 | if ( command == OPackage::Install && destination != QString::null ) | ||
273 | { | ||
274 | // TODO - Set destination for installs | ||
275 | cmdLine.append( "-dest" ); | ||
276 | cmdLine.append( destination ); | ||
277 | } | ||
278 | |||
279 | if ( command != OPackage::Update && command != OPackage::Download ) | ||
280 | { | ||
281 | if ( m_ipkgExecOptions & FORCE_DEPENDS ) | ||
282 | cmdLine.append( "-force-depends" ); | ||
283 | if ( m_ipkgExecOptions & FORCE_REINSTALL ) | ||
284 | cmdLine.append( "-force-reinstall" ); | ||
285 | if ( m_ipkgExecOptions & FORCE_REMOVE ) | ||
286 | cmdLine.append( "-force-removal-of-essential-packages" ); | ||
287 | if ( m_ipkgExecOptions & FORCE_OVERWRITE ) | ||
288 | cmdLine.append( "-force-overwrite" ); | ||
289 | if ( m_ipkgExecVerbosity == 3 ) | ||
290 | cmdLine.append( "-verbose_wget" ); | ||
291 | |||
292 | // TODO | ||
293 | // Handle make links | ||
294 | // Rules - If make links is switched on, create links to root | ||
295 | // if destDir is NOT / | ||
296 | /* | ||
297 | if ( m_ipkgExecOptions & MAKE_LINKS ) | ||
298 | { | ||
299 | // If destDir == / turn off make links as package is being insalled | ||
300 | // to root already. | ||
301 | if ( destDir == "/" ) | ||
302 | m_ipkgExecOptions ^= MAKE_LINKS; | ||
303 | } | ||
304 | */ | ||
305 | } | ||
306 | |||
307 | QString cmd; | ||
308 | switch( command ) | ||
309 | { | ||
310 | case OPackage::Install: cmd = "install"; | ||
311 | break; | ||
312 | case OPackage::Remove: cmd = "remove"; | ||
313 | break; | ||
314 | case OPackage::Update: cmd = "update"; | ||
315 | break; | ||
316 | case OPackage::Upgrade: cmd = "upgrade"; | ||
317 | break; | ||
318 | case OPackage::Download: cmd = "download"; | ||
319 | break; | ||
320 | case OPackage::Info: cmd = "info"; | ||
321 | break; | ||
322 | case OPackage::Files: cmd = "files"; | ||
323 | break; | ||
324 | //case OPackage::Version: cmd = "" ); | ||
325 | // break; | ||
326 | default: | ||
327 | break; | ||
328 | }; | ||
329 | cmdLine.append( cmd ); | ||
330 | |||
331 | // TODO | ||
332 | // If we are removing, reinstalling or upgrading packages and make links option is selected | ||
333 | // create the links | ||
334 | /* | ||
335 | if ( command == Remove || command == Upgrade ) | ||
336 | { | ||
337 | createLinks = false; | ||
338 | if ( flags & MAKE_LINKS ) | ||
339 | { | ||
340 | emit outputText( tr( "Removing symbolic links...\n" ) ); | ||
341 | linkPackage( Utils::getPackageNameFromIpkFilename( package ), destination, destDir ); | ||
342 | emit outputText( QString( " " ) ); | ||
343 | } | ||
344 | } | ||
345 | */ | ||
346 | // Append package list (if any) to end of command line | ||
347 | if ( parameters && !parameters->isEmpty() ) | ||
348 | { | ||
349 | for ( QStringList::Iterator it = parameters->begin(); it != parameters->end(); ++it ) | ||
350 | { | ||
351 | cmdLine.append( *it ); | ||
352 | } | ||
353 | } | ||
354 | |||
355 | // Create OProcess | ||
356 | if ( m_ipkgProcess ) | ||
357 | delete m_ipkgProcess; | ||
358 | m_ipkgProcess = new OProcess( cmdLine, this ); | ||
359 | |||
360 | // Connect signals (if any) | ||
361 | if ( receiver ) | ||
362 | { | ||
363 | if ( rawOutput ) | ||
364 | { | ||
365 | if ( slotOutput ) | ||
366 | connect( m_ipkgProcess, SIGNAL(receivedStdout(OProcess*,char*,int)), receiver, slotOutput ); | ||
367 | if ( slotErrors ) | ||
368 | connect( m_ipkgProcess, SIGNAL(receivedStderr(OProcess*,char*,int)), receiver, slotErrors ); | ||
369 | if ( slotFinished ) | ||
370 | connect( m_ipkgProcess, SIGNAL(processExited(OProcess*)), receiver, slotFinished ); | ||
371 | } | ||
372 | else // !rawOutput | ||
373 | { | ||
374 | // TODO - how should it handle partial lines? (i.e. "Installing opi", "e-aqpkg...") | ||
375 | } | ||
376 | } | ||
377 | |||
378 | // Run process | ||
379 | printf( "Running: \'%s\'\n", cmdLine.join( " " ).latin1() ); | ||
380 | return m_ipkgProcess->start( OProcess::NotifyOnExit, OProcess::All ); | ||
381 | } | ||
382 | |||
383 | void OIpkg::abortCommand() | ||
384 | { | ||
385 | if ( m_ipkgProcess ) | ||
386 | delete m_ipkgProcess; | ||
387 | } | ||
388 | |||
389 | void OIpkg::loadConfiguration() | ||
390 | { | ||
391 | if ( m_confInfo ) | ||
392 | delete m_confInfo; | ||
393 | |||
394 | // Load configuration item list | ||
395 | m_confInfo = new OConfItemList(); | ||
396 | |||
397 | QStringList confFiles; | ||
398 | QDir confDir( IPKG_CONF_DIR ); | ||
399 | if ( confDir.exists() ) | ||
400 | { | ||
401 | confDir.setNameFilter( "*.conf" ); | ||
402 | confDir.setFilter( QDir::Files ); | ||
403 | confFiles = confDir.entryList( "*.conf", QDir::Files ); | ||
404 | confFiles << IPKG_CONF; | ||
405 | |||
406 | for ( QStringList::Iterator it = confFiles.begin(); it != confFiles.end(); ++it ) | ||
407 | { | ||
408 | // Create absolute file path if necessary | ||
409 | QString absFile = (*it); | ||
410 | if ( !absFile.startsWith( "/" ) ) | ||
411 | absFile.prepend( QString( IPKG_CONF_DIR ) + "/" ); | ||
412 | |||
413 | // Read in file | ||
414 | QFile f( absFile ); | ||
415 | if ( f.open( IO_ReadOnly ) ) | ||
416 | { | ||
417 | QTextStream s( &f ); | ||
418 | while ( !s.eof() ) | ||
419 | { | ||
420 | |||
421 | QString line = s.readLine().simplifyWhiteSpace(); | ||
422 | |||
423 | // Parse line and save info to the conf options list | ||
424 | if ( !line.isEmpty() ) | ||
425 | { | ||
426 | if ( !line.startsWith( "#" ) || | ||
427 | line.startsWith( "#src" ) || | ||
428 | line.startsWith( "#dest" ) || | ||
429 | line.startsWith( "#arch" ) || | ||
430 | line.startsWith( "#option" ) ) | ||
431 | { | ||
432 | int pos = line.find( ' ', 1 ); | ||
433 | |||
434 | // Type | ||
435 | QString typeStr = line.left( pos ); | ||
436 | OConfItem::Type type; | ||
437 | if ( typeStr == "src" || typeStr == "#src" ) | ||
438 | type = OConfItem::Source; | ||
439 | else if ( typeStr == "dest" || typeStr == "#dest" ) | ||
440 | type = OConfItem::Destination; | ||
441 | else if ( typeStr == "option" || typeStr == "#option" ) | ||
442 | type = OConfItem::Option; | ||
443 | else if ( typeStr == "arch" || typeStr == "#arch" ) | ||
444 | type = OConfItem::Arch; | ||
445 | else | ||
446 | type = OConfItem::NotDefined; | ||
447 | ++pos; | ||
448 | int endpos = line.find( ' ', pos ); | ||
449 | |||
450 | // Name | ||
451 | QString name = line.mid( pos, endpos - pos ); | ||
452 | |||
453 | // Value | ||
454 | QString value = ""; | ||
455 | if ( endpos > -1 ) | ||
456 | value = line.right( line.length() - endpos - 1 ); | ||
457 | |||
458 | // Active | ||
459 | bool active = !line.startsWith( "#" ); | ||
460 | |||
461 | // Add to list | ||
462 | m_confInfo->append( new OConfItem( absFile, type, name, value, active ) ); | ||
463 | } | ||
464 | } | ||
465 | } | ||
466 | |||
467 | f.close(); | ||
468 | } | ||
469 | } | ||
470 | } | ||
471 | |||
472 | // Load Ipkg execution options from application configuration file | ||
473 | if ( m_config ) | ||
474 | { | ||
475 | m_config->setGroup( "Ipkg" ); | ||
476 | m_ipkgExecOptions = m_config->readNumEntry( "ExecOptions", m_ipkgExecOptions ); | ||
477 | m_ipkgExecVerbosity = m_config->readNumEntry( "Verbosity", m_ipkgExecVerbosity ); | ||
478 | } | ||
479 | } | ||
480 | |||
481 | OConfItemList *OIpkg::filterConfItems( OConfItem::Type typefilter ) | ||
482 | { | ||
483 | // Load Ipkg configuration info if not already cached | ||
484 | if ( !m_confInfo ) | ||
485 | loadConfiguration(); | ||
486 | |||
487 | // Build new server list (caller is responsible for deleting) | ||
488 | OConfItemList *sl = new OConfItemList; | ||
489 | |||
490 | // If typefilter is empty, retrieve all items | ||
491 | bool retrieveAll = ( typefilter == OConfItem::NotDefined ); | ||
492 | |||
493 | // Parse configuration info for servers | ||
494 | OConfItemListIterator it( *m_confInfo ); | ||
495 | for ( ; it.current(); ++it ) | ||
496 | { | ||
497 | OConfItem *item = it.current(); | ||
498 | if ( retrieveAll || item->type() == typefilter ) | ||
499 | { | ||
500 | sl->append( item ); | ||
501 | } | ||
502 | } | ||
503 | |||
504 | return sl; | ||
505 | } | ||