• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

  • tdecore
  • tdehw
tdestoragedevice.cpp
1 /* This file is part of the TDE libraries
2  Copyright (C) 2012 Timothy Pearson <kb9vqf@pearsoncomputing.net>
3  (C) 2013 Golubev Alexander <fatzer2@gmail.com>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 #include "tdestoragedevice.h"
21 
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <sys/ioctl.h>
26 #include <linux/cdrom.h>
27 
28 #include <tqregexp.h>
29 #include <tqpixmap.h>
30 #include <tqfile.h>
31 
32 #include "tdelocale.h"
33 #include "tdeglobal.h"
34 #include "kiconloader.h"
35 #include "tdetempfile.h"
36 #include "kstandarddirs.h"
37 
38 #include "tdehardwaredevices.h"
39 
40 #include "config.h"
41 
42 // uDisks2 integration
43 #if defined(WITH_UDISKS) || defined(WITH_UDISKS2)
44  #include <tqdbusdata.h>
45  #include <tqdbusmessage.h>
46  #include <tqdbusproxy.h>
47  #include <tqdbusvariant.h>
48  #include <tqdbusconnection.h>
49  #include <tqdbuserror.h>
50  #include <tqdbusdatamap.h>
51  #include <tqdbusobjectpath.h>
52 #endif // defined(WITH_UDISKS) || defined(WITH_UDISKS2)
53 #if defined(WITH_UDISKS)
54  #include "tqdbusdatalist.h"
55 #endif // ddefined(WITH_UDISKS)
56 
57 #if defined(WITH_UDISKS) || defined(WITH_UDISKS2)
58  // Defined in tdehardwaredevices.cpp
59  TQT_DBusData convertDBUSDataToVariantData(TQT_DBusData);
60 #endif // defined(WITH_UDISKS) || defined(WITH_UDISKS2)
61 
62 TDEStorageDevice::TDEStorageDevice(TDEGenericDeviceType::TDEGenericDeviceType dt, TQString dn) : TDEGenericDevice(dt, dn), m_mediaInserted(true) {
63  m_diskType = TDEDiskDeviceType::Null;
64  m_diskStatus = TDEDiskDeviceStatus::Null;
65 }
66 
67 TDEStorageDevice::~TDEStorageDevice() {
68 }
69 
70 TDEDiskDeviceType::TDEDiskDeviceType TDEStorageDevice::diskType() {
71  return m_diskType;
72 }
73 
74 void TDEStorageDevice::internalSetDiskType(TDEDiskDeviceType::TDEDiskDeviceType dt) {
75  m_diskType = dt;
76 }
77 
78 bool TDEStorageDevice::isDiskOfType(TDEDiskDeviceType::TDEDiskDeviceType tf) {
79  return ((m_diskType&tf)!=TDEDiskDeviceType::Null);
80 }
81 
82 TDEDiskDeviceStatus::TDEDiskDeviceStatus TDEStorageDevice::diskStatus() {
83  return m_diskStatus;
84 }
85 
86 void TDEStorageDevice::internalSetDiskStatus(TDEDiskDeviceStatus::TDEDiskDeviceStatus st) {
87  m_diskStatus = st;
88 }
89 
90 bool TDEStorageDevice::checkDiskStatus(TDEDiskDeviceStatus::TDEDiskDeviceStatus sf) {
91  return ((m_diskStatus&sf)!=(TDEDiskDeviceStatus::TDEDiskDeviceStatus)0);
92 }
93 
94 bool TDEStorageDevice::lockDriveMedia(bool lock) {
95  int fd = open(deviceNode().ascii(), O_RDWR | O_NONBLOCK);
96  if (fd < 0) {
97  return false;
98  }
99  if (ioctl(fd, CDROM_LOCKDOOR, (lock)?1:0) != 0) {
100  close(fd);
101  return false;
102  }
103  else {
104  close(fd);
105  return true;
106  }
107 }
108 
109 bool ejectDriveUDisks(TDEStorageDevice* sdevice) {
110 #ifdef WITH_UDISKS
111  TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus);
112  if (dbusConn.isConnected()) {
113  TQString blockDeviceString = sdevice->deviceNode();
114  blockDeviceString.replace("/dev/", "");
115  blockDeviceString = "/org/freedesktop/UDisks/devices/" + blockDeviceString;
116 
117  // Eject the drive!
118  TQT_DBusError error;
119  TQT_DBusProxy driveControl("org.freedesktop.UDisks", blockDeviceString, "org.freedesktop.UDisks.Device", dbusConn);
120  if (driveControl.canSend()) {
121  TQValueList<TQT_DBusData> params;
122  TQT_DBusDataList options;
123  params << TQT_DBusData::fromList(options);
124  TQT_DBusMessage reply = driveControl.sendWithReply("DriveEject", params, &error);
125  if (error.isValid()) {
126  // Error!
127  printf("[ERROR][tdehwlib] ejectDriveUDisks: %s\n", error.name().ascii()); fflush(stdout);
128  return FALSE;
129  }
130  else {
131  return TRUE;
132  }
133  }
134  }
135 #endif // WITH_UDISKS
136  return FALSE;
137 }
138 
139 bool ejectDriveUDisks2(TDEStorageDevice* sdevice) {
140 #ifdef WITH_UDISKS2
141  TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus);
142  if (dbusConn.isConnected()) {
143  TQString blockDeviceString = sdevice->deviceNode();
144  blockDeviceString.replace("/dev/", "");
145  blockDeviceString = "/org/freedesktop/UDisks2/block_devices/" + blockDeviceString;
146  TQT_DBusProxy hardwareControl("org.freedesktop.UDisks2", blockDeviceString, "org.freedesktop.DBus.Properties", dbusConn);
147  if (hardwareControl.canSend()) {
148  // get associated udisks2 drive path
149  TQT_DBusError error;
150  TQValueList<TQT_DBusData> params;
151  params << TQT_DBusData::fromString("org.freedesktop.UDisks2.Block") << TQT_DBusData::fromString("Drive");
152  TQT_DBusMessage reply = hardwareControl.sendWithReply("Get", params, &error);
153  if (error.isValid()) {
154  // Error!
155  printf("[ERROR][tdehwlib] ejectDriveUDisks2: %s\n", error.name().ascii()); fflush(stdout);
156  return FALSE;
157  }
158  else {
159  if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1) {
160  TQT_DBusObjectPath driveObjectPath = reply[0].toVariant().value.toObjectPath();
161  if (!driveObjectPath.isValid()) {
162  return FALSE;
163  }
164 
165  error = TQT_DBusError();
166  TQT_DBusProxy driveInformation("org.freedesktop.UDisks2", driveObjectPath, "org.freedesktop.DBus.Properties", dbusConn);
167  // can eject?
168  TQValueList<TQT_DBusData> params;
169  params << TQT_DBusData::fromString("org.freedesktop.UDisks2.Drive") << TQT_DBusData::fromString("Ejectable");
170  TQT_DBusMessage reply = driveInformation.sendWithReply("Get", params, &error);
171  if (error.isValid()) {
172  // Error!
173  printf("[ERROR][tdehwlib] ejectDriveUDisks2: %s\n", error.name().ascii()); fflush(stdout);
174  return FALSE;
175  }
176  if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1) {
177  bool ejectable = reply[0].toVariant().value.toBool();
178  if (!ejectable) {
179  return FALSE;
180  }
181 
182  // Eject the drive!
183  TQT_DBusProxy driveControl("org.freedesktop.UDisks2", driveObjectPath, "org.freedesktop.UDisks2.Drive", dbusConn);
184  TQValueList<TQT_DBusData> params;
185  TQT_DBusDataMap<TQString> options(TQT_DBusData::Variant);
186  params << TQT_DBusData::fromStringKeyMap(options);
187  TQT_DBusMessage reply = driveControl.sendWithReply("Eject", params, &error);
188  if (error.isValid()) {
189  // Error!
190  printf("[ERROR][tdehwlib] ejectDriveUDisks2: %s\n", error.name().ascii()); fflush(stdout);
191  return FALSE;
192  }
193  else {
194  return TRUE;
195  }
196  }
197  }
198  }
199  }
200  }
201 #endif // WITH_UDISKS2
202  return FALSE;
203 }
204 
205 int mountDriveUDisks(TQString deviceNode, TQString fileSystemType, TQStringList mountOptions, TQString* errStr = NULL) {
206 #ifdef WITH_UDISKS
207  TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus);
208  if (dbusConn.isConnected()) {
209  TQString blockDeviceString = deviceNode;
210  blockDeviceString.replace("/dev/", "");
211  blockDeviceString = "/org/freedesktop/UDisks/devices/" + blockDeviceString;
212 
213  // Mount the drive!
214  TQT_DBusError error;
215  TQT_DBusProxy driveControl("org.freedesktop.UDisks", blockDeviceString, "org.freedesktop.UDisks.Device", dbusConn);
216  if (driveControl.canSend()) {
217  TQValueList<TQT_DBusData> params;
218  params << TQT_DBusData::fromString(fileSystemType);
219  params << TQT_DBusData::fromList(TQT_DBusDataList(mountOptions));
220  TQT_DBusMessage reply = driveControl.sendWithReply("FilesystemMount", params, &error);
221  if (error.isValid()) {
222  // Error!
223  if (error.name() == "org.freedesktop.DBus.Error.ServiceUnknown") {
224  // Service not installed or unavailable
225  return -2;
226  }
227  if (errStr) {
228  *errStr = error.name() + ": " + error.message();
229  }
230  else {
231  printf("[ERROR][tdehwlib] mountDriveUDisks: %s\n", error.name().ascii()); fflush(stdout);
232  }
233  return -1;
234  }
235  else {
236  return 0;
237  }
238  }
239  else {
240  return -2;
241  }
242  }
243 #endif // WITH_UDISKS
244  return -2;
245 }
246 
247 int mountDriveUDisks2(TQString deviceNode, TQString fileSystemType, TQString mountOptions, TQString* errStr = NULL) {
248 #ifdef WITH_UDISKS2
249  TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus);
250  if (dbusConn.isConnected()) {
251  TQString blockDeviceString = deviceNode;
252  blockDeviceString.replace("/dev/", "");
253  blockDeviceString = "/org/freedesktop/UDisks2/block_devices/" + blockDeviceString;
254 
255  // Mount the drive!
256  TQT_DBusError error;
257  TQT_DBusProxy driveControl("org.freedesktop.UDisks2", blockDeviceString, "org.freedesktop.UDisks2.Filesystem", dbusConn);
258  if (driveControl.canSend()) {
259  TQValueList<TQT_DBusData> params;
260  TQMap<TQString, TQT_DBusData> optionsMap;
261  if (fileSystemType != "") {
262  optionsMap["fstype"] = convertDBUSDataToVariantData(TQT_DBusData::fromString(fileSystemType));
263  }
264  optionsMap["options"] = convertDBUSDataToVariantData(TQT_DBusData::fromString(mountOptions));
265  params << TQT_DBusData::fromStringKeyMap(TQT_DBusDataMap<TQString>(optionsMap));
266  TQT_DBusMessage reply = driveControl.sendWithReply("Mount", params, &error);
267  if (error.isValid()) {
268  // Error!
269  if (error.name() == "org.freedesktop.DBus.Error.ServiceUnknown") {
270  // Service not installed or unavailable
271  return -2;
272  }
273  if (errStr) {
274  *errStr = error.name() + ": " + error.message();
275  }
276  else {
277  printf("[ERROR][tdehwlib] mountDriveUDisks2: %s\n", error.name().ascii()); fflush(stdout);
278  }
279  return -1;
280  }
281  else {
282  return 0;
283  }
284  }
285  else {
286  return -2;
287  }
288  }
289 #endif // WITH_UDISKS2
290  return -2;
291 }
292 
293 int unMountDriveUDisks(TQString deviceNode, TQStringList unMountOptions, TQString* errStr = NULL) {
294 #ifdef WITH_UDISKS
295  TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus);
296  if (dbusConn.isConnected()) {
297  TQString blockDeviceString = deviceNode;
298  blockDeviceString.replace("/dev/", "");
299  blockDeviceString = "/org/freedesktop/UDisks/devices/" + blockDeviceString;
300 
301  // Mount the drive!
302  TQT_DBusError error;
303  TQT_DBusProxy driveControl("org.freedesktop.UDisks", blockDeviceString, "org.freedesktop.UDisks.Device", dbusConn);
304  if (driveControl.canSend()) {
305  TQValueList<TQT_DBusData> params;
306  params << TQT_DBusData::fromList(TQT_DBusDataList(unMountOptions));
307  TQT_DBusMessage reply = driveControl.sendWithReply("FilesystemUnmount", params, &error);
308  if (error.isValid()) {
309  // Error!
310  if (error.name() == "org.freedesktop.DBus.Error.ServiceUnknown") {
311  // Service not installed or unavailable
312  return -2;
313  }
314  if (errStr) {
315  *errStr = error.name() + ": " + error.message();
316  }
317  else {
318  printf("[ERROR][tdehwlib] unMountDriveUDisks: %s\n", error.name().ascii()); fflush(stdout);
319  }
320  return -1;
321  }
322  else {
323  return 0;
324  }
325  }
326  else {
327  return -2;
328  }
329  }
330 #endif // WITH_UDISKS
331  return -2;
332 }
333 
334 int unMountDriveUDisks2(TQString deviceNode, TQString unMountOptions, TQString* errStr = NULL) {
335 #ifdef WITH_UDISKS2
336  TQT_DBusConnection dbusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus);
337  if (dbusConn.isConnected()) {
338  TQString blockDeviceString = deviceNode;
339  blockDeviceString.replace("/dev/", "");
340  blockDeviceString = "/org/freedesktop/UDisks2/block_devices/" + blockDeviceString;
341 
342  // Mount the drive!
343  TQT_DBusError error;
344  TQT_DBusProxy driveControl("org.freedesktop.UDisks2", blockDeviceString, "org.freedesktop.UDisks2.Filesystem", dbusConn);
345  if (driveControl.canSend()) {
346  TQValueList<TQT_DBusData> params;
347  TQMap<TQString, TQT_DBusData> optionsMap;
348  optionsMap["options"] = convertDBUSDataToVariantData(TQT_DBusData::fromString(unMountOptions));
349  params << TQT_DBusData::fromStringKeyMap(TQT_DBusDataMap<TQString>(optionsMap));
350  TQT_DBusMessage reply = driveControl.sendWithReply("Unmount", params, &error);
351  if (error.isValid()) {
352  // Error!
353  if (error.name() == "org.freedesktop.DBus.Error.ServiceUnknown") {
354  // Service not installed or unavailable
355  return -2;
356  }
357  if (errStr) {
358  *errStr = error.name() + ": " + error.message();
359  }
360  else {
361  printf("[ERROR][tdehwlib] unMountDriveUDisks2: %s\n", error.name().ascii()); fflush(stdout);
362  }
363  return -1;
364  }
365  else {
366  return 0;
367  }
368  }
369  else {
370  return -2;
371  }
372  }
373 #endif // WITH_UDISKS2
374  return -2;
375 }
376 
377 bool TDEStorageDevice::ejectDrive() {
378 #ifdef WITH_UDISKS2
379  if (!(TDEGlobal::dirs()->findExe("udisksctl").isEmpty())) {
380  if (ejectDriveUDisks2(this)) {
381  return TRUE;
382  }
383  else {
384  printf("[tdehwlib] Failed to eject drive '%s' via udisks2, falling back to alternate mechanism\n", deviceNode().ascii());
385  fflush(stdout);
386  }
387  }
388 #endif // WITH_UDISKS2
389 
390 #ifdef WITH_UDISKS
391  if (!(TDEGlobal::dirs()->findExe("udisks").isEmpty())) {
392  if (ejectDriveUDisks(this)) {
393  return TRUE;
394  }
395  else {
396  printf("[tdehwlib] Failed to eject drive '%s' via udisks, falling back to alternate mechanism\n", deviceNode().ascii());
397  fflush(stdout);
398  }
399  }
400 #endif // WITH_UDISKS
401 
402  if (!(TDEGlobal::dirs()->findExe("eject").isEmpty())) {
403  TQString command = TQString("eject -v '%1' 2>&1").arg(deviceNode());
404 
405  FILE *exepipe = popen(command.ascii(), "r");
406  if (exepipe) {
407  TQString eject_output;
408  TQTextStream ts(exepipe, IO_ReadOnly);
409  eject_output = ts.read();
410  int retcode = pclose(exepipe);
411  if (retcode == 0) {
412  return TRUE;
413  }
414  }
415  printf("[tdehwlib] Failed to eject drive '%s' via 'eject' command\n", deviceNode().ascii());
416  fflush(stdout);
417  }
418 
419  return FALSE;
420 }
421 
422 bool TDEStorageDevice::ejectDriveMedia() {
423  int fd = open(deviceNode().ascii(), O_RDWR | O_NONBLOCK);
424  if (fd < 0) {
425  return false;
426  }
427  if (ioctl(fd, CDROMEJECT) != 0) {
428  close(fd);
429  return false;
430  }
431  else {
432  close(fd);
433  return true;
434  }
435 }
436 
437 TQString TDEStorageDevice::diskLabel() {
438  return m_diskName;
439 }
440 
441 void TDEStorageDevice::internalSetDiskLabel(TQString dn) {
442  m_diskName = dn;
443 }
444 
445 bool TDEStorageDevice::mediaInserted() {
446  return m_mediaInserted;
447 }
448 
449 void TDEStorageDevice::internalSetMediaInserted(bool inserted) {
450  m_mediaInserted = inserted;
451 }
452 
453 TQString TDEStorageDevice::fileSystemName() {
454  return m_fileSystemName;
455 }
456 
457 void TDEStorageDevice::internalSetFileSystemName(TQString fn) {
458  m_fileSystemName = fn;
459 }
460 
461 TQString TDEStorageDevice::fileSystemUsage() {
462  return m_fileSystemUsage;
463 }
464 
465 void TDEStorageDevice::internalSetFileSystemUsage(TQString fu) {
466  m_fileSystemUsage = fu;
467 }
468 
469 TQString TDEStorageDevice::diskUUID() {
470  return m_diskUUID;
471 }
472 
473 void TDEStorageDevice::internalSetDiskUUID(TQString id) {
474  m_diskUUID = id;
475 }
476 
477 TQStringList TDEStorageDevice::holdingDevices() {
478  return m_holdingDevices;
479 }
480 
481 void TDEStorageDevice::internalSetHoldingDevices(TQStringList hd) {
482  m_holdingDevices = hd;
483 }
484 
485 TQStringList TDEStorageDevice::slaveDevices() {
486  return m_slaveDevices;
487 }
488 
489 void TDEStorageDevice::internalSetSlaveDevices(TQStringList sd) {
490  m_slaveDevices = sd;
491 }
492 
493 TQString decodeHexEncoding(TQString str) {
494  TQRegExp hexEncRegExp("\\\\x[0-9A-Fa-f]{1,2}");
495  hexEncRegExp.setMinimal(false);
496  hexEncRegExp.setCaseSensitive(true);
497  int s = -1;
498 
499  while((s = hexEncRegExp.search(str, s+1))>=0){
500  str.replace(s, hexEncRegExp.cap(0).length(), TQChar((char)strtol(hexEncRegExp.cap(0).mid(2).ascii(), NULL, 16)));
501  }
502 
503  return str;
504 }
505 
506 TQString TDEStorageDevice::friendlyName() {
507  // Return the actual storage device name
508  TQString devicevendorid = vendorEncoded();
509  TQString devicemodelid = modelEncoded();
510 
511  devicevendorid = decodeHexEncoding(devicevendorid);
512  devicemodelid = decodeHexEncoding(devicemodelid);
513 
514  devicevendorid = devicevendorid.stripWhiteSpace();
515  devicemodelid = devicemodelid.stripWhiteSpace();
516  devicevendorid = devicevendorid.simplifyWhiteSpace();
517  devicemodelid = devicemodelid.simplifyWhiteSpace();
518 
519  TQString devicename = devicevendorid + " " + devicemodelid;
520 
521  devicename = devicename.stripWhiteSpace();
522  devicename = devicename.simplifyWhiteSpace();
523 
524  if (devicename != "") {
525  return devicename;
526  }
527 
528  if (isDiskOfType(TDEDiskDeviceType::Camera)) {
529  return TDEGenericDevice::friendlyName();
530  }
531 
532  if (isDiskOfType(TDEDiskDeviceType::Floppy)) {
533  return friendlyDeviceType();
534  }
535 
536  TQString label = diskLabel();
537  if (label.isNull()) {
538  if (deviceSize() > 0) {
539  if (checkDiskStatus(TDEDiskDeviceStatus::Hotpluggable)) {
540  label = i18n("%1 Removable Device").arg(deviceFriendlySize());
541  }
542  else {
543  label = i18n("%1 Fixed Storage Device").arg(deviceFriendlySize());
544  }
545  }
546  }
547 
548  if (!label.isNull()) {
549  return label;
550  }
551 
552  return friendlyDeviceType();
553 }
554 
555 TQString TDEStorageDevice::detailedFriendlyName() {
556  return TQString("%1 [%2]").arg(friendlyName()).arg(deviceNode());
557 }
558 
559 TQString TDEStorageDevice::friendlyDeviceType() {
560  TQString ret = i18n("Hard Disk Drive");
561 
562  // Keep this in sync with TDEStorageDevice::icon(TDEIcon::StdSizes size) below
563  if (isDiskOfType(TDEDiskDeviceType::Floppy)) {
564  ret = i18n("Floppy Drive");
565  }
566  if (isDiskOfType(TDEDiskDeviceType::Optical)) {
567  ret = i18n("Optical Drive");
568  }
569  if (isDiskOfType(TDEDiskDeviceType::CDROM)) {
570  ret = i18n("CDROM Drive");
571  }
572  if (isDiskOfType(TDEDiskDeviceType::CDRW)) {
573  ret = i18n("CDRW Drive");
574  }
575  if (isDiskOfType(TDEDiskDeviceType::DVDROM)) {
576  ret = i18n("DVD Drive");
577  }
578  if (isDiskOfType(TDEDiskDeviceType::DVDRW)) {
579  ret = i18n("DVDRW Drive");
580  }
581  if (isDiskOfType(TDEDiskDeviceType::DVDRAM)) {
582  ret = i18n("DVDRAM Drive");
583  }
584  if (isDiskOfType(TDEDiskDeviceType::Zip)) {
585  ret = i18n("Zip Drive");
586  }
587  if (isDiskOfType(TDEDiskDeviceType::Tape)) {
588  ret = i18n("Tape Drive");
589  }
590  if (isDiskOfType(TDEDiskDeviceType::Camera)) {
591  ret = i18n("Digital Camera");
592  }
593 
594  if (isDiskOfType(TDEDiskDeviceType::HDD)) {
595  ret = i18n("Hard Disk Drive");
596  if (checkDiskStatus(TDEDiskDeviceStatus::Hotpluggable)) {
597  ret = i18n("Removable Storage");
598  }
599  if (isDiskOfType(TDEDiskDeviceType::CompactFlash)) {
600  ret = i18n("Compact Flash");
601  }
602  if (isDiskOfType(TDEDiskDeviceType::MemoryStick)) {
603  ret = i18n("Memory Stick");
604  }
605  if (isDiskOfType(TDEDiskDeviceType::SmartMedia)) {
606  ret = i18n("Smart Media");
607  }
608  if (isDiskOfType(TDEDiskDeviceType::SDMMC)) {
609  ret = i18n("Secure Digital");
610  }
611  }
612 
613  if (isDiskOfType(TDEDiskDeviceType::RAM)) {
614  ret = i18n("Random Access Memory");
615  }
616  if (isDiskOfType(TDEDiskDeviceType::Loop)) {
617  ret = i18n("Loop Device");
618  }
619 
620  return ret;
621 }
622 
623 TQPixmap TDEStorageDevice::icon(TDEIcon::StdSizes size) {
624  TQString mountString;
625  if (mountPath() != TQString::null) {
626  mountString = "-mounted";
627  }
628 
629  TQPixmap ret = DesktopIcon("drive-harddisk" + mountString, size);
630 
631  if (isDiskOfType(TDEDiskDeviceType::Floppy)) {
632  ret = DesktopIcon("media-floppy-3_5" + mountString, size);
633  }
634  if (isDiskOfType(TDEDiskDeviceType::Optical)) {
635  ret = DesktopIcon("media-optical-cdrom" + mountString, size);
636  }
637  if (isDiskOfType(TDEDiskDeviceType::CDROM)) {
638  ret = DesktopIcon("media-optical-cdrom" + mountString, size);
639  }
640  if (isDiskOfType(TDEDiskDeviceType::CDRW)) {
641  ret = DesktopIcon("media-optical-cdwriter" + mountString, size);
642  }
643  if (isDiskOfType(TDEDiskDeviceType::DVDROM)) {
644  ret = DesktopIcon("media-optical-dvd" + mountString, size);
645  }
646  if (isDiskOfType(TDEDiskDeviceType::DVDRW)) {
647  ret = DesktopIcon("media-optical-dvd" + mountString, size);
648  }
649  if (isDiskOfType(TDEDiskDeviceType::DVDRAM)) {
650  ret = DesktopIcon("media-optical-dvd" + mountString, size);
651  }
652  if (isDiskOfType(TDEDiskDeviceType::Zip)) {
653  ret = DesktopIcon("media-floppy-zip" + mountString, size);
654  }
655  if (isDiskOfType(TDEDiskDeviceType::Tape)) {
656  ret = DesktopIcon("media-tape" + mountString, size);
657  }
658  if (isDiskOfType(TDEDiskDeviceType::Camera)) {
659  ret = DesktopIcon("camera" + TQString((mountPath() != TQString::null) ? "_mount" : "_umount"), size);
660  }
661 
662  if (isDiskOfType(TDEDiskDeviceType::HDD)) {
663  ret = DesktopIcon("drive-harddisk" + mountString, size);
664  if (checkDiskStatus(TDEDiskDeviceStatus::Hotpluggable)) {
665  ret = DesktopIcon("media-flash-usb" + mountString, size);
666  }
667  if (isDiskOfType(TDEDiskDeviceType::CompactFlash)) {
668  ret = DesktopIcon("media-flash-compact_flash" + mountString, size);
669  }
670  if (isDiskOfType(TDEDiskDeviceType::MemoryStick)) {
671  ret = DesktopIcon("media-flash-memory_stick" + mountString, size);
672  }
673  if (isDiskOfType(TDEDiskDeviceType::SmartMedia)) {
674  ret = DesktopIcon("media-flash-smart_media" + mountString, size);
675  }
676  if (isDiskOfType(TDEDiskDeviceType::SDMMC)) {
677  ret = DesktopIcon("media-flash-sd_mmc" + mountString, size);
678  }
679  }
680 
681  if (isDiskOfType(TDEDiskDeviceType::RAM)) {
682  ret = DesktopIcon("memory" + mountString, size);
683  }
684  if (isDiskOfType(TDEDiskDeviceType::Loop)) {
685  ret = DesktopIcon("blockdevice" + mountString, size);
686  }
687 
688  return ret;
689 }
690 
691 unsigned long long TDEStorageDevice::deviceSize() {
692  TQString bsnodename = systemPath();
693  // While at first glance it would seem that checking /queue/physical_block_size would be needed to get an accurate device size, in reality Linux
694  // appears to only ever report the device size in 512 byte units. This does not appear to be documented anywhere!
695  TQString blocksize = "512";
696 
697  TQString dsnodename = systemPath();
698  dsnodename.append("/size");
699  TQFile dsfile( dsnodename );
700  TQString devicesize;
701  if ( dsfile.open( IO_ReadOnly ) ) {
702  TQTextStream stream( &dsfile );
703  devicesize = stream.readLine();
704  dsfile.close();
705  }
706 
707  return ((unsigned long long)blocksize.toULong()*(unsigned long long)devicesize.toULong());
708 }
709 
710 TQString TDEStorageDevice::deviceFriendlySize() {
711  return TDEHardwareDevices::bytesToFriendlySizeString(deviceSize());
712 }
713 
714 TQString TDEStorageDevice::mountPath() {
715  // See if this device node is mounted
716  // This requires parsing /proc/mounts, looking for deviceNode()
717 
718  // The Device Mapper throws a monkey wrench into this
719  // It likes to advertise mounts as /dev/mapper/<something>,
720  // where <something> is listed in <system path>/dm/name
721 
722  // First, ensure that all device information (mainly holders/slaves) is accurate
723  TDEGlobal::hardwareDevices()->rescanDeviceInformation(this);
724 
725  TQString dmnodename = systemPath();
726  dmnodename.append("/dm/name");
727  TQFile namefile( dmnodename );
728  TQString dmaltname;
729  if ( namefile.open( IO_ReadOnly ) ) {
730  TQTextStream stream( &namefile );
731  dmaltname = stream.readLine();
732  namefile.close();
733  }
734  if (!dmaltname.isNull()) {
735  dmaltname.prepend("/dev/mapper/");
736  }
737 
738  TQStringList lines;
739  TQFile file( "/proc/mounts" );
740  if ( file.open( IO_ReadOnly ) ) {
741  TQTextStream stream( &file );
742  TQString line;
743  while ( !stream.atEnd() ) {
744  line = stream.readLine();
745  TQStringList mountInfo = TQStringList::split(" ", line, true);
746  TQString testNode = *mountInfo.at(0);
747  // Check for match
748  if ((testNode == deviceNode()) || (testNode == dmaltname) || (testNode == ("/dev/disk/by-uuid/" + diskUUID()))) {
749  TQString ret = *mountInfo.at(1);
750  ret.replace("\\040", " ");
751  return ret;
752  }
753  lines += line;
754  }
755  file.close();
756  }
757 
758  // While this device is not directly mounted, it could concievably be mounted via the Device Mapper
759  // If so, try to retrieve the mount path...
760  TQStringList slaveDeviceList = holdingDevices();
761  for ( TQStringList::Iterator slavedevit = slaveDeviceList.begin(); slavedevit != slaveDeviceList.end(); ++slavedevit ) {
762  // Try to locate this device path in the TDE device tree
763  TDEHardwareDevices *hwdevices = TDEGlobal::hardwareDevices();
764  TDEGenericDevice *hwdevice = hwdevices->findBySystemPath(*slavedevit);
765  if ((hwdevice) && (hwdevice->type() == TDEGenericDeviceType::Disk)) {
766  TDEStorageDevice* sdevice = static_cast<TDEStorageDevice*>(hwdevice);
767  return sdevice->mountPath();
768  }
769  }
770 
771  return TQString::null;
772 }
773 
774 TQString TDEStorageDevice::mountDevice(TQString mediaName, TDEStorageMountOptions mountOptions, TQString* errRet, int* retcode) {
775  int internal_retcode;
776  if (!retcode) {
777  retcode = &internal_retcode;
778  }
779 
780  TQString ret = mountPath();
781 
782  // Device is already mounted
783  if (!ret.isNull()) {
784  return ret;
785  }
786 
787  TQString command;
788  TQString devNode = deviceNode();
789  devNode.replace("'", "'\\''");
790  mediaName.replace("'", "'\\''");
791 
792 #if defined(WITH_UDISKS2) || defined(WITH_UDISKS)
793  // Prepare filesystem options for mount
794  TQStringList udisksOptions;
795  TQString optionString;
796 
797  if (mountOptions["ro"] == "true") {
798  udisksOptions.append("ro");
799  }
800 
801  if (mountOptions["atime"] != "true") {
802  udisksOptions.append("noatime");
803  }
804 
805  if (mountOptions["sync"] == "true") {
806  udisksOptions.append("sync");
807  }
808 
809  if( (mountOptions["filesystem"] == "fat")
810  || (mountOptions["filesystem"] == "vfat")
811  || (mountOptions["filesystem"] == "msdos")
812  || (mountOptions["filesystem"] == "umsdos")
813  ) {
814  if (mountOptions.contains("shortname")) {
815  udisksOptions.append(TQString("shortname=%1").arg(mountOptions["shortname"]));
816  }
817  }
818 
819  if( (mountOptions["filesystem"] == "jfs")) {
820  if (mountOptions["utf8"] == "true") {
821  // udisks/udisks2 for now does not support option iocharset= for jfs
822  // udisksOptions.append("iocharset=utf8");
823  }
824  }
825 
826  if( (mountOptions["filesystem"] == "ntfs-3g") ) {
827  if (mountOptions.contains("locale")) {
828  udisksOptions.append(TQString("locale=%1").arg(mountOptions["locale"]));
829  }
830  }
831 
832  if( (mountOptions["filesystem"] == "ext3")
833  || (mountOptions["filesystem"] == "ext4")
834  ) {
835  if (mountOptions.contains("journaling")) {
836  // udisks/udisks2 for now does not support option data= for ext3/ext4
837  // udisksOptions.append(TQString("data=%1").arg(mountOptions["journaling"]));
838  }
839  }
840 
841  for (TQStringList::Iterator it = udisksOptions.begin(); it != udisksOptions.end(); ++it) {
842  optionString.append(",");
843  optionString.append(*it);
844  }
845 
846  if (!optionString.isEmpty()) {
847  optionString.remove(0, 1);
848  }
849 #endif // defined(WITH_UDISKS2) || defined(WITH_UDISKS)
850 
851 #ifdef WITH_UDISKS2
852  if(command.isEmpty()) {
853  // Try to use UDISKS v2 via DBUS, if available
854  TQString errorString;
855  TQString fileSystemType;
856 
857  if (mountOptions.contains("filesystem") && !mountOptions["filesystem"].isEmpty()) {
858  fileSystemType = mountOptions["filesystem"];
859  }
860 
861  int uDisks2Ret = mountDriveUDisks2(devNode, fileSystemType, optionString, &errorString);
862  if (uDisks2Ret == 0) {
863  // Update internal mount data
864  TDEGlobal::hardwareDevices()->processModifiedMounts();
865 
866  ret = mountPath();
867  return ret;
868  }
869  else if (uDisks2Ret == -1) {
870  if (errRet) {
871  *errRet = errorString;
872  }
873 
874  // Update internal mount data
875  TDEGlobal::hardwareDevices()->processModifiedMounts();
876 
877  ret = mountPath();
878  return ret;
879  }
880  else {
881  // The UDISKS v2 DBUS service was either not available or was unusable; try another method...
882  command = TQString::null;
883  }
884  }
885 #endif // WITH_UDISKS2
886 
887 #ifdef WITH_UDISKS
888  if(command.isEmpty()) {
889  // Try to use UDISKS v1 via DBUS, if available
890  TQString errorString;
891  TQString fileSystemType;
892 
893  if (mountOptions.contains("filesystem") && !mountOptions["filesystem"].isEmpty()) {
894  fileSystemType = mountOptions["filesystem"];
895  }
896 
897  int uDisksRet = mountDriveUDisks(devNode, fileSystemType, udisksOptions, &errorString);
898  if (uDisksRet == 0) {
899  // Update internal mount data
900  TDEGlobal::hardwareDevices()->processModifiedMounts();
901 
902  ret = mountPath();
903  return ret;
904  }
905  else if (uDisksRet == -1) {
906  if (errRet) {
907  *errRet = errorString;
908  }
909 
910  // Update internal mount data
911  TDEGlobal::hardwareDevices()->processModifiedMounts();
912 
913  ret = mountPath();
914  return ret;
915  }
916  else {
917  // The UDISKS v1 DBUS service was either not available or was unusable; try another method...
918  command = TQString::null;
919  }
920  }
921 #endif // WITH_UDISKS
922 
923  if(command.isEmpty()) {
924  // Use 'pmount' command, if available
925  TQString pmountProg = TDEGlobal::dirs()->findExe("pmount");
926  if (!pmountProg.isEmpty()) {
927  // Create dummy password file
928  KTempFile passwordFile(TQString::null, "tmp", 0600);
929  passwordFile.setAutoDelete(true);
930 
931  TQString optionString;
932  if (mountOptions["ro"] == "true") {
933  optionString.append(" -r");
934  }
935 
936  if (mountOptions["atime"] != "true") {
937  optionString.append(" -A");
938  }
939 
940  if (mountOptions["utf8"] == "true") {
941  optionString.append(" -c utf8");
942  }
943 
944  if (mountOptions["sync"] == "true") {
945  optionString.append(" -s");
946  }
947 
948  if (mountOptions.contains("filesystem") && !mountOptions["filesystem"].isEmpty()) {
949  optionString.append(TQString(" -t %1").arg(mountOptions["filesystem"]));
950  }
951 
952  if (mountOptions.contains("locale")) {
953  optionString.append(TQString(" -c %1").arg(mountOptions["locale"]));
954  }
955 
956  TQString mountpoint;
957  if (mountOptions.contains("mountpoint")
958  && !mountOptions["mountpoint"].isEmpty()
959  && (mountOptions["mountpoint"] != "/media/")) {
960  mountpoint = mountOptions["mountpoint"];
961  mountpoint.replace("'", "'\\''");
962  }
963  else {
964  mountpoint = mediaName;
965  }
966 
967  TQString passFileName = passwordFile.name();
968  passFileName.replace("'", "'\\''");
969 
970  command = TQString("pmount -p '%1' %2 '%3' '%4' 2>&1").arg(passFileName).arg(optionString).arg(devNode).arg(mountpoint);
971  }
972  }
973 
974  if(command.isEmpty()) {
975  if (errRet) {
976  *errRet = i18n("No supported mounting methods were detected on your system");
977  }
978  return ret;
979  }
980 
981  FILE *exepipe = popen(command.local8Bit(), "r");
982  if (exepipe) {
983  TQString mount_output;
984  TQTextStream* ts = new TQTextStream(exepipe, IO_ReadOnly);
985  mount_output = ts->read();
986  delete ts;
987  *retcode = pclose(exepipe);
988  if (errRet) {
989  *errRet = mount_output;
990  }
991  }
992 
993  // Update internal mount data
994  TDEGlobal::hardwareDevices()->processModifiedMounts();
995 
996  ret = mountPath();
997 
998  return ret;
999 }
1000 
1001 TQString TDEStorageDevice::mountEncryptedDevice(TQString passphrase, TQString mediaName, TDEStorageMountOptions mountOptions, TQString* errRet, int* retcode) {
1002  int internal_retcode;
1003  if (!retcode) {
1004  retcode = &internal_retcode;
1005  }
1006 
1007  TQString ret = mountPath();
1008 
1009  if (!ret.isNull()) {
1010  return ret;
1011  }
1012 
1013  // Create dummy password file
1014  KTempFile passwordFile(TQString::null, "tmp", 0600);
1015  passwordFile.setAutoDelete(true);
1016  TQFile* pwFile = passwordFile.file();
1017  if (!pwFile) {
1018  return TQString::null;
1019  }
1020 
1021  pwFile->writeBlock(passphrase.ascii(), passphrase.length());
1022  pwFile->flush();
1023 
1024  TQString optionString;
1025  if (mountOptions["ro"] == "true") {
1026  optionString.append(" -r");
1027  }
1028 
1029  if (mountOptions["atime"] != "true") {
1030  optionString.append(" -A");
1031  }
1032 
1033  if (mountOptions["utf8"] == "true") {
1034  optionString.append(" -c utf8");
1035  }
1036 
1037  if (mountOptions["sync"] == "true") {
1038  optionString.append(" -s");
1039  }
1040 
1041  if (mountOptions.contains("filesystem") && !mountOptions["filesystem"].isEmpty()) {
1042  optionString.append(TQString(" -t %1").arg(mountOptions["filesystem"]));
1043  }
1044 
1045  if (mountOptions.contains("locale")) {
1046  optionString.append(TQString(" -c %1").arg(mountOptions["locale"]));
1047  }
1048 
1049  TQString passFileName = passwordFile.name();
1050  TQString devNode = deviceNode();
1051  passFileName.replace("'", "'\\''");
1052  devNode.replace("'", "'\\''");
1053  mediaName.replace("'", "'\\''");
1054  TQString command = TQString("pmount -p '%1' %2 '%3' '%4' 2>&1").arg(passFileName).arg(optionString).arg(devNode).arg(mediaName);
1055 
1056  FILE *exepipe = popen(command.local8Bit(), "r");
1057  if (exepipe) {
1058  TQString mount_output;
1059  TQTextStream* ts = new TQTextStream(exepipe, IO_ReadOnly);
1060  mount_output = ts->read();
1061  delete ts;
1062  *retcode = pclose(exepipe);
1063  if (errRet) {
1064  *errRet = mount_output;
1065  }
1066  }
1067 
1068  // Update internal mount data
1069  TDEGlobal::hardwareDevices()->processModifiedMounts();
1070 
1071  ret = mountPath();
1072 
1073  return ret;
1074 }
1075 
1076 bool TDEStorageDevice::unmountDevice(TQString* errRet, int* retcode) {
1077  int internal_retcode;
1078  if (!retcode) {
1079  retcode = &internal_retcode;
1080  }
1081 
1082  TQString mountpoint = mountPath();
1083  TQString devNode = deviceNode();
1084 
1085  if (mountpoint.isNull()) {
1086  return true;
1087  }
1088 
1089  mountpoint.replace("'", "'\\''");
1090 
1091  TQString command;
1092 
1093 #ifdef WITH_UDISKS2
1094  if(command.isEmpty()) {
1095  // Try to use UDISKS v2 via DBUS, if available
1096  TQString errorString;
1097  int unMountUDisks2Ret = unMountDriveUDisks2(devNode, TQString::null, &errorString);
1098  if (unMountUDisks2Ret == 0) {
1099  // Update internal mount data
1100  TDEGlobal::hardwareDevices()->processModifiedMounts();
1101 
1102  return true;
1103  }
1104  else if (unMountUDisks2Ret == -1) {
1105  if (errRet) {
1106  *errRet = errorString;
1107  }
1108 
1109  // Update internal mount data
1110  TDEGlobal::hardwareDevices()->processModifiedMounts();
1111 
1112  return false;
1113  }
1114  else {
1115  // The UDISKS v2 DBUS service was either not available or was unusable; try another method...
1116  command = TQString::null;
1117  }
1118  }
1119 #endif // WITH_UDISKS2
1120 #ifdef WITH_UDISKS
1121  if(command.isEmpty()) {
1122  // Try to use UDISKS v1 via DBUS, if available
1123  TQString errorString;
1124  int unMountUDisksRet = unMountDriveUDisks(devNode, TQStringList(), &errorString);
1125  if (unMountUDisksRet == 0) {
1126  // Update internal mount data
1127  TDEGlobal::hardwareDevices()->processModifiedMounts();
1128 
1129  return true;
1130  }
1131  else if (unMountUDisksRet == -1) {
1132  if (errRet) {
1133  *errRet = errorString;
1134  }
1135 
1136  // Update internal mount data
1137  TDEGlobal::hardwareDevices()->processModifiedMounts();
1138 
1139  return false;
1140  }
1141  else {
1142  // The UDISKS v1 DBUS service was either not available or was unusable; try another method...
1143  command = TQString::null;
1144  }
1145  }
1146 #endif // WITH_UDISKS
1147  if(command.isEmpty() &&
1148  !(TDEGlobal::dirs()->findExe("pumount").isEmpty())) {
1149  command = TQString("pumount '%1' 2>&1").arg(mountpoint);
1150  }
1151 
1152  if(command.isEmpty()) {
1153  if (errRet) {
1154  *errRet = i18n("No supported unmounting methods were detected on your system");
1155  }
1156  return true;
1157  }
1158 
1159  FILE *exepipe = popen(command.local8Bit(), "r");
1160  if (exepipe) {
1161  TQString umount_output;
1162  TQTextStream* ts = new TQTextStream(exepipe, IO_ReadOnly);
1163  umount_output = ts->read();
1164  delete ts;
1165  *retcode = pclose(exepipe);
1166  if (*retcode == 0) {
1167  // Update internal mount data
1168  TDEGlobal::hardwareDevices()->processModifiedMounts();
1169 
1170  return true;
1171  }
1172  else {
1173  if (errRet) {
1174  *errRet = umount_output;
1175  }
1176  }
1177  }
1178 
1179  // Update internal mount data
1180  TDEGlobal::hardwareDevices()->processModifiedMounts();
1181 
1182  return false;
1183 }
1184 
1185 TQString TDEStorageDevice::determineFileSystemType(TQString path) {
1186  TQStringList mountTable;
1187  TQString prevPath = path;
1188  dev_t prevDev = 0;
1189  int pos;
1190  struct stat directory_info;
1191  if (path.startsWith("/")) {
1192  stat(path.local8Bit(), &directory_info);
1193  prevDev = directory_info.st_dev;
1194  // Walk the directory tree up to the root, checking for any change in st_dev
1195  // If a change is found, the previous value of path is the mount point itself
1196  while (path != "/") {
1197  pos = path.findRev("/", -1, TRUE);
1198  if (pos < 0) {
1199  break;
1200  }
1201  path = path.mid(0, pos);
1202  if (path == "") {
1203  path = "/";
1204  }
1205  stat(path.local8Bit(), &directory_info);
1206  if (directory_info.st_dev != prevDev) {
1207  break;
1208  }
1209  prevPath = path;
1210  prevDev = directory_info.st_dev;
1211  }
1212  }
1213 
1214  // Read in mount table
1215  mountTable.clear();
1216  TQFile file( "/proc/mounts" );
1217  if ( file.open( IO_ReadOnly ) ) {
1218  TQTextStream stream( &file );
1219  while ( !stream.atEnd() ) {
1220  mountTable.append(stream.readLine());
1221  }
1222  file.close();
1223  }
1224 
1225  // Parse mount table
1226  TQStringList::Iterator it;
1227  for ( it = mountTable.begin(); it != mountTable.end(); ++it ) {
1228  TQStringList mountInfo = TQStringList::split(" ", (*it), true);
1229  if ((*mountInfo.at(1)) == prevPath) {
1230  return (*mountInfo.at(2));
1231  }
1232  }
1233 
1234  // Unknown file system type
1235  return TQString::null;
1236 }
1237 
1238 #include "tdestoragedevice.moc"
TDEStdAccel::open
const TDEShortcut & open()
Open file.
Definition: tdestdaccel.cpp:270
TDEGlobal::hardwareDevices
static TDEHardwareDevices * hardwareDevices()
Returns a TDEHardwareDevices object.
TDEGlobal::dirs
static TDEStandardDirs * dirs()
Returns the application standard dirs object.
Definition: tdeglobal.cpp:58
tdelocale.h
TDEIcon::StdSizes
StdSizes
These are the standard sizes for icons.
Definition: kicontheme.h:112
TDEStandardDirs::findExe
static TQString findExe(const TQString &appname, const TQString &pathstr=TQString::null, bool ignoreExecBit=false)
Finds the executable in the system path.
Definition: kstandarddirs.cpp:932
TDEStdAccel::close
const TDEShortcut & close()
Close current document.
Definition: tdestdaccel.cpp:272
KTempFile
The KTempFile class creates and opens a unique file for temporary use.
Definition: tdetempfile.h:55
TDEStdAccel::label
TQString label(StdAccel id)
Returns a localized label for user-visible display.
Definition: tdestdaccel.cpp:156

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.8.11
This website is maintained by Timothy Pearson.