TDE personal information management applications
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tdeio_mobile.cpp 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. /* This file is part of the KDE KMobile library
  2. Copyright (C) 2003 Helge Deller <deller@kde.org>
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Library General Public
  5. License version 2 as published by the Free Software Foundation.
  6. This library is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  9. Library General Public License for more details.
  10. You should have received a copy of the GNU Library General Public License
  11. along with this library; see the file COPYING.LIB. If not, write to
  12. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  13. Boston, MA 02110-1301, USA.
  14. */
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include <sys/types.h>
  18. #include <unistd.h>
  19. #include <time.h>
  20. #include <tqregexp.h>
  21. #include <kdebug.h>
  22. #include <tdelocale.h>
  23. #include <kinstance.h>
  24. #include <tdeabc/vcardconverter.h>
  25. #include "tdeio_mobile.h"
  26. #include <tdepimmacros.h>
  27. using namespace TDEIO;
  28. #define TDEIO_MOBILE_DEBUG_AREA 7126
  29. #define PRINT_DEBUG kdDebug(TDEIO_MOBILE_DEBUG_AREA) << "tdeio_mobile: "
  30. extern "C" { KDE_EXPORT int kdemain(int argc, char **argv); }
  31. /**
  32. * The main program.
  33. */
  34. int kdemain(int argc, char **argv)
  35. {
  36. TDEInstance instance( "tdeio_mobile" );
  37. PRINT_DEBUG << "Starting " << getpid() << endl;
  38. if (argc != 4) {
  39. fprintf(stderr, "Usage tdeio_mobile protocol pool app\n");
  40. return -1;
  41. }
  42. // let the protocol class do its work
  43. KMobileProtocol slave(argv[2], argv[3]);
  44. slave.dispatchLoop();
  45. PRINT_DEBUG << "Done" << endl;
  46. return 0;
  47. }
  48. /**
  49. * Initialize the mobile slave
  50. */
  51. KMobileProtocol::KMobileProtocol(const TQCString &pool, const TQCString &app)
  52. : SlaveBase( "mobile", pool, app)
  53. {
  54. }
  55. KMobileProtocol::~KMobileProtocol()
  56. {
  57. }
  58. /*
  59. * getDeviceAndRessource("mobile:/<devicename>/<resource>/...") - split
  60. */
  61. int KMobileProtocol::getDeviceAndRessource(const TQString &_path,
  62. TQString &devName, TQString &resource, TQString &devPath,
  63. KMobileDevice::Capabilities &devCaps)
  64. {
  65. // PRINT_DEBUG << TQString("###getDeviceAndRessource### %1\n").arg(_path);
  66. TQStringList path = TQStringList::split('/', _path, false);
  67. devName = resource = devPath = TQString();
  68. devCaps = KMobileDevice::hasNothing;
  69. if (path.count() >= 1) { devName = path[0]; path.pop_front(); };
  70. if (path.count() >= 1) { resource = path[0]; path.pop_front(); };
  71. if (path.count() >= 1) devPath = path.join("/");
  72. if (devName.isEmpty())
  73. return 0;
  74. int _caps = m_dev.capabilities(devName);
  75. if (resource.isEmpty()) {
  76. devCaps = (KMobileDevice::Capabilities) _caps;
  77. return 0;
  78. }
  79. for (int i=0; i<31; i++) {
  80. int cap = 1UL << i;
  81. if ((_caps & cap) == 0)
  82. continue;
  83. TQString capname = m_dev.nameForCap(devName,cap);
  84. if (capname != resource)
  85. continue;
  86. devCaps = (KMobileDevice::Capabilities) cap;
  87. return 0;
  88. }
  89. return TDEIO::ERR_DOES_NOT_EXIST;
  90. }
  91. static
  92. void addAtom(TDEIO::UDSEntry& entry, unsigned int ID, long l, const TQString& s = TQString())
  93. {
  94. TDEIO::UDSAtom atom;
  95. atom.m_uds = ID;
  96. atom.m_long = l;
  97. atom.m_str = s;
  98. entry.append(atom);
  99. }
  100. static
  101. void createDirEntry(TDEIO::UDSEntry& entry, const TQString& name, const TQString& url, const TQString& mime)
  102. {
  103. entry.clear();
  104. addAtom(entry, TDEIO::UDS_NAME, 0, name);
  105. addAtom(entry, TDEIO::UDS_FILE_TYPE, S_IFDIR);
  106. addAtom(entry, TDEIO::UDS_ACCESS, 0500);
  107. addAtom(entry, TDEIO::UDS_MIME_TYPE, 0, mime);
  108. addAtom(entry, TDEIO::UDS_URL, 0, url);
  109. addAtom(entry, TDEIO::UDS_USER, 0, getenv("USER"));
  110. addAtom(entry, TDEIO::UDS_GROUP, 0, getenv("USER"));
  111. PRINT_DEBUG << TQString("createDirEntry: File: %1 MIME: %2 URL: %3\n").arg(name).arg(mime).arg(url);
  112. // addAtom(entry, TDEIO::UDS_SIZE, 0);
  113. addAtom(entry, TDEIO::UDS_GUESSED_MIME_TYPE, 0, mime);
  114. }
  115. static
  116. void createFileEntry(TDEIO::UDSEntry& entry, const TQString& name, const TQString& url, const TQString& mime,
  117. const unsigned long size = 0)
  118. {
  119. entry.clear();
  120. addAtom(entry, TDEIO::UDS_NAME, 0, name);
  121. addAtom(entry, TDEIO::UDS_FILE_TYPE, S_IFREG);
  122. addAtom(entry, TDEIO::UDS_URL, 0, url);
  123. addAtom(entry, TDEIO::UDS_ACCESS, 0400);
  124. addAtom(entry, TDEIO::UDS_USER, 0, getenv("USER"));
  125. addAtom(entry, TDEIO::UDS_GROUP, 0, getenv("USER"));
  126. addAtom(entry, TDEIO::UDS_MIME_TYPE, 0, mime);
  127. if (size) addAtom(entry, TDEIO::UDS_SIZE, size);
  128. addAtom(entry, TDEIO::UDS_GUESSED_MIME_TYPE, 0, mime);
  129. PRINT_DEBUG << TQString("createFileEntry: File: %1, Size: %2, MIME: %3\n").arg(name).arg(size).arg(mime);
  130. }
  131. /**
  132. * Get the information contained in the URL.
  133. */
  134. void KMobileProtocol::get(const KURL &url)
  135. {
  136. PRINT_DEBUG << "###############################\n";
  137. PRINT_DEBUG << TQString("get(%1)\n").arg(url.path());
  138. KMobileDevice::Capabilities devCaps;
  139. TQString devName, resource, devPath;
  140. int err = getDeviceAndRessource(url.path(), devName, resource, devPath, devCaps);
  141. if (err) {
  142. error(err, url.path());
  143. return;
  144. }
  145. if (devName.isEmpty() || resource.isEmpty()) {
  146. error(TDEIO::ERR_DOES_NOT_EXIST, url.path());
  147. return;
  148. }
  149. // collect the result
  150. TQCString result;
  151. TQString mime;
  152. switch (devCaps) {
  153. case KMobileDevice::hasAddressBook: err = getVCard(devName, result, mime, devPath);
  154. break;
  155. case KMobileDevice::hasCalendar: err = getCalendar(devName, result, mime, devPath);
  156. break;
  157. case KMobileDevice::hasNotes: err = getNote(devName, result, mime, devPath);
  158. break;
  159. case KMobileDevice::hasFileStorage: err = getFileStorage(devName, result, mime, devPath);
  160. break;
  161. default: err = TDEIO::ERR_CANNOT_ENTER_DIRECTORY; /* TODO */
  162. }
  163. if (err) {
  164. error(err, url.path());
  165. return;
  166. }
  167. // tell the mimetype
  168. mimeType(mime);
  169. // tell the length
  170. TDEIO::filesize_t processed_size = result.length();
  171. totalSize(processed_size);
  172. // tell the contents of the URL
  173. TQByteArray array;
  174. array.setRawData( result.data(), result.length() );
  175. data(array);
  176. array.resetRawData( result.data(), result.length() );
  177. processedSize( processed_size );
  178. // tell we are finished
  179. data(TQByteArray());
  180. // tell we are finished
  181. finished();
  182. }
  183. /*
  184. * listRoot() - gives listing of all devices
  185. */
  186. void KMobileProtocol::listRoot(const KURL& url)
  187. {
  188. PRINT_DEBUG << TQString("########## listRoot(%1) for %2:/\n").arg(url.path()).arg(url.protocol());
  189. TDEIO::UDSEntry entry;
  190. TQStringList deviceNames = m_dev.deviceNames();
  191. unsigned int dirs = deviceNames.count();
  192. totalSize(dirs);
  193. int classMask = KMobileDevice::Unclassified;
  194. /* handle all possible protocols here and just add a <protocol>.protocol file */
  195. if (url.protocol() == "cellphone") // cellphone:/
  196. classMask = KMobileDevice::Phone;
  197. if (url.protocol() == "organizer" || // organizer:/
  198. url.protocol() == "pda") // pda:/
  199. classMask = KMobileDevice::Organizer;
  200. if (url.protocol() == "phonecamera") // camera:/
  201. classMask = KMobileDevice::Camera;
  202. for (unsigned int i=0; i<dirs; i++) {
  203. TQString devName = deviceNames[i];
  204. if (classMask != KMobileDevice::Unclassified &&
  205. m_dev.classType(devName) != classMask)
  206. continue;
  207. createDirEntry(entry, devName, "mobile:/"+devName,
  208. KMOBILE_MIMETYPE_DEVICE_KONQUEROR(devName));
  209. listEntry(entry, false);
  210. processedSize(i+1);
  211. }
  212. listEntry(entry, true);
  213. finished();
  214. }
  215. /*
  216. * folderMimeType() - returns mimetype of the folder itself
  217. */
  218. TQString KMobileProtocol::folderMimeType(int cap)
  219. {
  220. TQString mimetype;
  221. switch (cap) {
  222. case KMobileDevice::hasAddressBook: mimetype = KMOBILE_MIMETYPE_INODE "addressbook";
  223. break;
  224. case KMobileDevice::hasCalendar: mimetype = KMOBILE_MIMETYPE_INODE "calendar";
  225. break;
  226. case KMobileDevice::hasNotes: mimetype = KMOBILE_MIMETYPE_INODE "notes";
  227. break;
  228. case KMobileDevice::hasFileStorage:
  229. default: mimetype = "inode/directory";
  230. }
  231. return mimetype;
  232. }
  233. /*
  234. * entryMimeType() - returns mimetype of the entries in the given folder
  235. */
  236. TQString KMobileProtocol::entryMimeType(int cap)
  237. {
  238. TQString mimetype;
  239. switch (cap) {
  240. case KMobileDevice::hasAddressBook: mimetype = "text/x-vcard";
  241. break;
  242. case KMobileDevice::hasCalendar: mimetype = "text/x-vcalendar";
  243. break;
  244. case KMobileDevice::hasNotes: mimetype = "text/plain";
  245. break;
  246. case KMobileDevice::hasFileStorage:
  247. default: mimetype = "text/plain";
  248. }
  249. return mimetype;
  250. }
  251. /*
  252. * listTopDeviceDir("mobile:/<devicename>") - sub-directory of a devices
  253. */
  254. void KMobileProtocol::listTopDeviceDir(const TQString &devName)
  255. {
  256. PRINT_DEBUG << TQString("listTopDeviceDir(%1)\n").arg(devName);
  257. TDEIO::UDSEntry entry;
  258. unsigned int caps = m_dev.capabilities(devName);
  259. for (int i=0; i<31; i++) {
  260. unsigned int cap = 1UL<<i;
  261. if ((caps & cap) == 0)
  262. continue;
  263. TQString filename = m_dev.nameForCap(devName, cap);
  264. TQString mimetype = folderMimeType(cap);
  265. createDirEntry(entry, filename, TQString("mobile:/%1/%2/").arg(devName).arg(filename), mimetype);
  266. listEntry(entry, false);
  267. }
  268. listEntry(entry, true);
  269. finished();
  270. }
  271. /*
  272. * listEntries("mobile:/<devicename>/<resource>") - resources of a device
  273. */
  274. void KMobileProtocol::listEntries(const TQString &devName,
  275. const TQString &resource, const TQString &devPath,
  276. const KMobileDevice::Capabilities devCaps)
  277. {
  278. PRINT_DEBUG << TQString("listEntries(%1,%2,%3)\n").arg(devName).arg(resource).arg(devPath);
  279. switch (devCaps) {
  280. case KMobileDevice::hasAddressBook: listAddressBook(devName, resource);
  281. break;
  282. case KMobileDevice::hasCalendar: listCalendar(devName, resource);
  283. break;
  284. case KMobileDevice::hasNotes: listNotes(devName, resource);
  285. break;
  286. case KMobileDevice::hasFileStorage: listFileStorage(devName, resource, devPath);
  287. break;
  288. default: error( ERR_CANNOT_ENTER_DIRECTORY,
  289. TQString("/%1/%2").arg(devName).arg(resource) );
  290. }
  291. }
  292. /*
  293. * listAddressBook("mobile:/<devicename>/Addressbook) - list the addressbook
  294. */
  295. void KMobileProtocol::listAddressBook(const TQString &devName, const TQString &resource)
  296. {
  297. PRINT_DEBUG << TQString("listAddressBook(%1)\n").arg(devName);
  298. TDEIO::UDSEntry entry;
  299. int fieldwidth;
  300. int entries = m_dev.numAddresses(devName);
  301. if (entries>=1000) fieldwidth=4; else
  302. if (entries>=100) fieldwidth=3; else
  303. if (entries>=10) fieldwidth=2; else fieldwidth=1;
  304. totalSize(entries);
  305. // TQRegExp rx; rx.setPattern( ".*FN:([\\w\\s]*)[\\n\\r]{2}.*" );
  306. TQString name;
  307. for (int i=0; i<entries; i++) {
  308. #if 0
  309. TQString content = m_dev.readAddress(devName, i);
  310. if ( rx.search( content ) < 0 )
  311. name = TQString();
  312. else
  313. name = "_" + rx.cap(1);
  314. #endif
  315. TQString filename = TQString("%1%2.vcf").arg(i,fieldwidth).arg(name);
  316. for (int p=0; p<fieldwidth; p++) {
  317. if (filename[p]==' ') filename[p]='0'; else break;
  318. }
  319. TQString url = TQString("mobile:/%1/%2/%3").arg(devName).arg(resource).arg(filename);
  320. createFileEntry(entry, filename, url, entryMimeType(KMobileDevice::hasAddressBook),
  321. 400 /*content.utf8().length()*/ );
  322. listEntry(entry, false);
  323. processedSize(i+1);
  324. }
  325. listEntry(entry, true);
  326. finished();
  327. }
  328. /*
  329. * getVCard() - gives the vCard of the given file
  330. */
  331. int KMobileProtocol::getVCard( const TQString &devName, TQCString &result, TQString &mime, const TQString &path )
  332. {
  333. PRINT_DEBUG << TQString("getVCard(%1)\n").arg(path);
  334. int index = path.find('.');
  335. if (index>0)
  336. index = path.left(index).toInt();
  337. if (index<0 || index>=m_dev.numAddresses(devName))
  338. return TDEIO::ERR_DOES_NOT_EXIST;
  339. TQString str = m_dev.readAddress(devName, index);
  340. if (str.isEmpty())
  341. return TDEIO::ERR_INTERNAL;
  342. result = str.utf8();
  343. mime = entryMimeType(KMobileDevice::hasAddressBook);
  344. // setMetaData("plugin", "const TQString &key, const TQString &value);
  345. return 0;
  346. }
  347. /*
  348. * listCalendar("mobile:/<devicename>/Calendar) - list the calendar entries
  349. */
  350. void KMobileProtocol::listCalendar( const TQString &devName, const TQString &resource)
  351. {
  352. PRINT_DEBUG << TQString("listCalendar(%1)\n").arg(devName);
  353. TDEIO::UDSEntry entry;
  354. int entries = m_dev.numCalendarEntries(devName);
  355. totalSize(entries);
  356. for (int i=0; i<entries; i++) {
  357. TQString filename = TQString("%1_%2.vcs").arg(i).arg(i18n("calendar"));
  358. TQString url = TQString("mobile:/%1/%2/%3").arg(devName).arg(resource).arg(filename);
  359. createFileEntry(entry, filename, url, entryMimeType(KMobileDevice::hasCalendar));
  360. listEntry(entry, false);
  361. processedSize(i+1);
  362. }
  363. listEntry(entry, true);
  364. finished();
  365. }
  366. /*
  367. * getCalendar() - reads a calendar entry
  368. */
  369. int KMobileProtocol::getCalendar( const TQString &devName, TQCString &result, TQString &mime, const TQString &path)
  370. {
  371. PRINT_DEBUG << TQString("getCalendar(%1, #%2)\n").arg(devName).arg(path);
  372. /* TODO */
  373. Q_UNUSED(result);
  374. Q_UNUSED(mime);
  375. return TDEIO::ERR_CANNOT_ENTER_DIRECTORY;
  376. }
  377. /*
  378. * listNotes("mobile:/<devicename>/Notes) - list the notes
  379. */
  380. void KMobileProtocol::listNotes( const TQString &devName, const TQString &resource)
  381. {
  382. PRINT_DEBUG << TQString("listNotes(%1)\n").arg(devName);
  383. TDEIO::UDSEntry entry;
  384. int entries = m_dev.numNotes(devName);
  385. totalSize(entries);
  386. for (int i=0; i<entries; i++) {
  387. TQString note /*= m_dev.readNote(devName, i)*/;
  388. TQString filename = TQString("%1_%2.txt").arg(i).arg(i18n("note"));
  389. TQString url = TQString("mobile:/%1/%2/%3").arg(devName).arg(resource).arg(filename);
  390. createFileEntry(entry, filename, url, entryMimeType(KMobileDevice::hasNotes),
  391. 0 /*note.utf8().length()*/);
  392. listEntry(entry, false);
  393. processedSize(i+1);
  394. }
  395. listEntry(entry, true);
  396. finished();
  397. }
  398. /*
  399. * getNote() - gives the Note of the given file
  400. */
  401. int KMobileProtocol::getNote( const TQString &devName, TQCString &result, TQString &mime, const TQString &path )
  402. {
  403. PRINT_DEBUG << TQString("getNote(%1)\n").arg(path);
  404. int index = path.find('_');
  405. if (index>0)
  406. index = path.left(index).toInt();
  407. if (index<0 || index>=m_dev.numNotes(devName))
  408. return TDEIO::ERR_DOES_NOT_EXIST;
  409. TQString note = m_dev.readNote(devName, index);
  410. if (note.isEmpty())
  411. return TDEIO::ERR_DOES_NOT_EXIST;
  412. result = note.utf8();
  413. mime = entryMimeType(KMobileDevice::hasNotes);
  414. return 0;
  415. }
  416. /*
  417. * listFileStorage("mobile:/<devicename>/Files) - list the files on the device
  418. */
  419. void KMobileProtocol::listFileStorage(const TQString &devName, const TQString &resource, const TQString &devPath)
  420. {
  421. PRINT_DEBUG << TQString("listFileStorage(%1,%2)\n").arg(devName).arg(devPath);
  422. /* TODO */
  423. error( TDEIO::ERR_DOES_NOT_EXIST, TQString("/%1/%2/%3").arg(devName).arg(resource).arg(devPath) );
  424. }
  425. /*
  426. * getFileStorage() - gives the file contents of the given file
  427. */
  428. int KMobileProtocol::getFileStorage(const TQString &devName, TQCString &result, TQString &mime, const TQString &path)
  429. {
  430. PRINT_DEBUG << TQString("getFileStorage(%1)\n").arg(path);
  431. /* TODO */
  432. Q_UNUSED(devName);
  433. Q_UNUSED(result);
  434. Q_UNUSED(mime);
  435. return TDEIO::ERR_CANNOT_ENTER_DIRECTORY;
  436. }
  437. /**
  438. * Test if the url contains a directory or a file.
  439. */
  440. void KMobileProtocol::stat( const KURL &url )
  441. {
  442. PRINT_DEBUG << "###############################\n";
  443. PRINT_DEBUG << TQString("stat(%1)\n").arg(url.path());
  444. KMobileDevice::Capabilities devCaps;
  445. TQString devName, resource, devPath;
  446. int err = getDeviceAndRessource(url.path(), devName, resource, devPath, devCaps);
  447. if (err) {
  448. error(err, url.path());
  449. return;
  450. }
  451. TQStringList path = TQStringList::split('/', url.path(), false);
  452. TQString filename = (path.count()>0) ? path[path.count()-1] : "/";
  453. TQString fullPath = path.join("/");
  454. TQString fullUrl = TQString("mobile:/%1").arg(fullPath);
  455. UDSEntry entry;
  456. bool isDir = devPath.isEmpty();
  457. if (isDir) {
  458. createDirEntry(entry, filename, fullUrl, folderMimeType(devCaps));
  459. } else {
  460. createFileEntry(entry, filename, fullUrl, entryMimeType(devCaps));
  461. }
  462. statEntry(entry);
  463. finished();
  464. }
  465. /**
  466. * Get the mimetype.
  467. */
  468. void KMobileProtocol::mimetype(const KURL &url)
  469. {
  470. PRINT_DEBUG << "###############################\n";
  471. PRINT_DEBUG << TQString("mimetype(%1)\n").arg(url.path());
  472. KMobileDevice::Capabilities devCaps;
  473. TQString devName, resource, devPath;
  474. int err = getDeviceAndRessource(url.path(), devName, resource, devPath, devCaps);
  475. if (err) {
  476. error(err, url.path());
  477. return;
  478. }
  479. // tell the mimetype
  480. mimeType(entryMimeType(devCaps));
  481. finished();
  482. }
  483. /**
  484. * List the contents of a directory.
  485. */
  486. void KMobileProtocol::listDir(const KURL &url)
  487. {
  488. PRINT_DEBUG << "###############################\n";
  489. PRINT_DEBUG << TQString("listDir(%1)\n").arg(url.path());
  490. if (!m_dev.isKMobileAvailable()) {
  491. error( TDEIO::ERR_CONNECTION_BROKEN, i18n("TDE Mobile Device Manager") );
  492. return;
  493. }
  494. KMobileDevice::Capabilities devCaps;
  495. TQString devName, resource, devPath;
  496. int err = getDeviceAndRessource(url.path(), devName, resource, devPath, devCaps);
  497. if (err) {
  498. error(err, url.path());
  499. return;
  500. }
  501. if (devName.isEmpty()) {
  502. listRoot(url);
  503. return;
  504. }
  505. #if 0
  506. if (!dev) {
  507. error( TDEIO::ERR_DOES_NOT_EXIST, TQString("/%1").arg(devName) );
  508. return;
  509. }
  510. #endif
  511. if (resource.isEmpty()) {
  512. listTopDeviceDir(devName);
  513. return;
  514. }
  515. listEntries(devName, resource, devPath, devCaps);
  516. }