001/* 002 * IzPack - Copyright 2001-2005 Julien Ponge, All Rights Reserved. 003 * 004 * http://www.izforge.com/izpack/ 005 * http://developer.berlios.de/projects/izpack/ 006 * 007 * Copyright 2003 Marc Eppelmann 008 * 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 */ 021 022/* 023 * This represents a Implementation of the KDE/GNOME DesktopEntry. 024 * which is standard from 025 * "Desktop Entry Standard" 026 * "The format of .desktop files, supported by KDE and GNOME." 027 * http://www.freedesktop.org/standards/desktop-entry-spec/ 028 * 029 * [Desktop Entry] 030 // Comment=$Comment 031 // Comment[de]= 032 // Encoding=$UTF-8 033 // Exec=$'/home/marc/CPS/tomcat/bin/catalina.sh' run 034 // GenericName=$ 035 // GenericName[de]=$ 036 // Icon=$inetd 037 // MimeType=$ 038 // Name=$Start Tomcat 039 // Name[de]=$Start Tomcat 040 // Path=$/home/marc/CPS/tomcat/bin/ 041 // ServiceTypes=$ 042 // SwallowExec=$ 043 // SwallowTitle=$ 044 // Terminal=$true 045 // TerminalOptions=$ 046 // Type=$Application 047 // X-KDE-SubstituteUID=$false 048 // X-KDE-Username=$ 049 * 050 */ 051package com.izforge.izpack.util.os; 052 053import java.io.BufferedReader; 054import java.io.BufferedWriter; 055import java.io.File; 056import java.io.FileReader; 057import java.io.FileWriter; 058import java.io.IOException; 059import java.util.Enumeration; 060import java.util.Properties; 061import java.util.StringTokenizer; 062import java.util.Vector; 063 064import com.izforge.izpack.util.FileExecutor; 065import com.izforge.izpack.util.OsVersion; 066import com.izforge.izpack.util.StringTool; 067 068/** 069 * This is the Implementation of the RFC-Based Desktop-Link. Used in KDE and GNOME. 070 * 071 * @author marc.eppelmann@reddot.des 072 */ 073public class Unix_Shortcut extends Shortcut implements Unix_ShortcutConstants 074{ 075 076 //~ Static fields/initializers 077 // ******************************************************************************************************************************* 078 079 /** version = "$Id: Unix_Shortcut.java,v 1.9 2005/07/27 08:57:07 jponge Exp $" */ 080 private static String version = "$Id: Unix_Shortcut.java,v 1.9 2005/07/27 08:57:07 jponge Exp $"; 081 082 /** rev = "$Revision: 1.9 $" */ 083 private static String rev = "$Revision: 1.9 $"; 084 085 /** DESKTOP_EXT = ".desktop" */ 086 private static String DESKTOP_EXT = ".desktop"; 087 088 /** template = "" */ 089 private static String template = ""; 090 091 /** N = "\n" */ 092 private final static String N = "\n"; 093 094 /** H = "#" */ 095 private final static String H = "#"; 096 097 /** S = " " */ 098 private final static String S = " "; 099 100 /** C = Comment = H+S = "# " */ 101 private final static String C = H + S; 102 103 /** QM = "\"" : <b>Q</b>uotation<b>M</b>ark */ 104 private final static String QM = "\""; 105 106 //~ Instance fields 107 // ****************************************************************************************************************************************** 108 109 /** internal String createdDirectory */ 110 private String createdDirectory; 111 112 /** internal int itsShow */ 113 private int itsShow; 114 115 /** internal int itsUserType */ 116 private int itsUserType; 117 118 /** internal int itsType */ 119 private int itsType; 120 121 /** internal int itsIconIndex */ 122 private int itsIconIndex; 123 124 /** internal String itsWorkingDirectory */ 125 private String itsWorkingDirectory; 126 127 /** internal String itsGroupName */ 128 private String itsGroupName; 129 130 /** internal String itsTargetPath */ 131 private String itsTargetPath; 132 133 /** internal String itsIconPath */ 134 private String itsIconPath; 135 136 /** internal String itsDescription */ 137 private String itsDescription; 138 139 /** internal String itsArguments */ 140 private String itsArguments; 141 142 /** internal String itsName */ 143 private String itsName; 144 145 /** internal String itsFileName */ 146 private String itsFileName; 147 148 /** internal String itsApplnkFolder = "applnk" */ 149 private String itsApplnkFolder = "applnk"; 150 151 /** internal Properties Set */ 152 private Properties props; 153 154 /** forAll = new Boolean(false): A flag to indicate that this should created for all users. */ 155 private Boolean forAll = new Boolean(false); 156 157 //~ Constructors 158 // ********************************************************************************************************************************************* 159 160 /** 161 * Creates a new Unix_Shortcut object. 162 */ 163 public Unix_Shortcut() 164 { 165 StringBuffer hlp = new StringBuffer(); 166 167 String userLanguage = System.getProperty("user.language", "en"); 168 169 hlp.append("[Desktop Entry]" + N); 170 171 hlp.append("Comment=" + $Comment + N); 172 hlp.append("Comment[" + userLanguage + "]=" + $Comment + N); 173 hlp.append("Encoding=" + $Encoding + N); 174 175 hlp.append("Exec="+ $E_QUOT + $Exec + $E_QUOT + S + $Arguments + N); 176 hlp.append("GenericName=" + $GenericName + N); 177 178 hlp.append("GenericName[" + userLanguage + "]=" + $GenericName + N); 179 hlp.append("Icon=" + $Icon + N); 180 hlp.append("MimeType=" + $MimeType + N); 181 hlp.append("Name=" + $Name + N); 182 hlp.append("Name[" + userLanguage + "]=" + $Name + N); 183 184 hlp.append("Path="+ $P_QUOT + $Path + $P_QUOT + N); 185 hlp.append("ServiceTypes=" + $ServiceTypes + N); 186 hlp.append("SwallowExec=" + $SwallowExec + N); 187 hlp.append("SwallowTitle=" + $SwallowTitle + N); 188 hlp.append("Terminal=" + $Terminal + N); 189 190 hlp.append("TerminalOptions=" + $Options_For_Terminal + N); 191 hlp.append("Type=" + $Type + N); 192 hlp.append("URL=" + $URL + N); 193 hlp.append("X-KDE-SubstituteUID=" + $X_KDE_SubstituteUID + N); 194 hlp.append("X-KDE-Username=" + $X_KDE_Username + N); 195 hlp.append(N); 196 hlp.append(C + "created by" + S + getClass().getName() + S + rev + N ); 197 hlp.append(C + version ); 198 199 template = hlp.toString(); 200 201 props = new Properties(); 202 203 initProps(); 204 } 205 206 //~ Methods 207 // ************************************************************************************************************************************************** 208 209 /** 210 * This initialisizes all Properties Values with null. 211 */ 212 private void initProps() 213 { 214 String[] propsArray = { $Comment, $$LANG_Comment, $Encoding, $Exec, $Arguments, 215 $GenericName, $$LANG_GenericName, $MimeType, $Name, $$LANG_Name, $Path, 216 $ServiceTypes, $SwallowExec, $SwallowTitle, $Terminal, $Options_For_Terminal, 217 $Type, $X_KDE_SubstituteUID, $X_KDE_Username, $Icon, $URL, $E_QUOT, $P_QUOT }; 218 219 for (int i = 0; i < propsArray.length; i++) 220 { 221 props.put(propsArray[i], ""); 222 } 223 } 224 225 /** 226 * Overridden Method 227 * 228 * @see com.izforge.izpack.util.os.Shortcut#initialize(int, java.lang.String) 229 */ 230 public void initialize(int aType, String aName) throws Exception 231 { 232 this.itsType = aType; 233 this.itsName = aName; 234 props.put($Name, aName); 235 } 236 237 /** 238 * This indicates that Unix will be supported. 239 * 240 * @see com.izforge.izpack.util.os.Shortcut#supported() 241 */ 242 public boolean supported() 243 { 244 return true; 245 } 246 247 /** 248 * Dummy 249 * 250 * @see com.izforge.izpack.util.os.Shortcut#getDirectoryCreated() 251 */ 252 public String getDirectoryCreated() 253 { 254 return this.createdDirectory; //while not stored... 255 } 256 257 /** 258 * Dummy 259 * 260 * @see com.izforge.izpack.util.os.Shortcut#getFileName() 261 */ 262 public String getFileName() 263 { 264 return (this.itsFileName); 265 } 266 267 /** 268 * Overridden compatibility method. Returns all directories in $USER/.kde/share/applink. 269 * 270 * @see com.izforge.izpack.util.os.Shortcut#getProgramGroups(int) 271 */ 272 public Vector getProgramGroups(int userType) 273 { 274 Vector groups = new Vector(); 275 276 File kdeShareApplnk = getKdeShareApplnkFolder(userType); 277 278 try 279 { 280 File[] listing = kdeShareApplnk.listFiles(); 281 282 for (int i = 0; i < listing.length; i++) 283 { 284 if (listing[i].isDirectory()) 285 { 286 groups.add(listing[i].getName()); 287 } 288 } 289 } 290 catch (Exception e) 291 { 292 // ignore and return an empty vector. 293 } 294 295 return (groups); 296 } 297 298 /** 299 * Gets the Programsfolder for the given User (non-Javadoc). 300 * 301 * @see com.izforge.izpack.util.os.Shortcut#getProgramsFolder(int) 302 */ 303 public String getProgramsFolder(int current_user) 304 { 305 String result = new String(); 306 307 // 308 result = getKdeShareApplnkFolder(current_user).toString(); 309 310 return result; 311 } 312 313 /** 314 * Gets the kde/share/applink - Folder for the given user and for the currently known and 315 * supported distribution. 316 * 317 * @param userType to get for. 318 * 319 * @return the users or the systems kde share/applink(-redhat/-mdk) 320 */ 321 private File getKdeShareApplnkFolder(int userType) 322 { 323 File kdeBase = getKdeBase(userType); 324 325 File result = new File(kdeBase + File.separator + "share" + File.separator 326 + getKdeApplinkFolderName()); 327 328 return result; 329 } 330 331 /** 332 * Gets the name of the applink folder for the currently used distribution. Currently 333 * "applnk-redhat for RedHat, "applnk-mdk" for Mandrake, and simply "applnk" for all others. 334 * 335 * @return result 336 */ 337 private String getKdeApplinkFolderName() 338 { 339 String applinkFolderName = "applnk"; 340 341 if (OsVersion.IS_REDHAT_LINUX) 342 { 343 applinkFolderName = "applnk-redhat"; 344 } 345 346 if (OsVersion.IS_MANDRAKE_LINUX) 347 { 348 applinkFolderName = "applnk-mdk"; 349 } 350 351 return applinkFolderName; 352 } 353 354 /** 355 * Gets the KDEBasedir for the given User. 356 * 357 * @param userType one of root or regular user 358 * 359 * @return the basedir 360 */ 361 private File getKdeBase(int userType) 362 { 363 File result = null; 364 365 if (userType == Shortcut.ALL_USERS) 366 { 367 FileExecutor fe = new FileExecutor(); 368 369 String[] execOut = new String[2]; 370 371 int execResult = fe.executeCommand(new String[] { "/usr/bin/env", "kde-config", 372 "--prefix"}, execOut); 373 374 result = new File(execOut[0].trim()); 375 } 376 else 377 { 378 result = new File(System.getProperty("user.home").toString() + File.separator + ".kde"); 379 } 380 return result; 381 } 382 383 /** 384 * overridden method 385 * 386 * @return true 387 * 388 * @see com.izforge.izpack.util.os.Shortcut#multipleUsers() 389 */ 390 public boolean multipleUsers() 391 { 392 // EVER true for UNIXes ;-) 393 return (true); 394 } 395 396 /** 397 * Creates and stores the shortcut-files. 398 * 399 * @see com.izforge.izpack.util.os.Shortcut#save() 400 */ 401 public void save() throws Exception 402 { 403 String FS = File.separator; 404 String target = null; 405 406 String shortCutDef = this.replace(); 407 408 boolean rootUser4All = this.getUserType() == Shortcut.ALL_USERS; 409 boolean create4All = this.getCreateForAll().booleanValue(); 410 411 if ("".equals(this.itsGroupName) && this.getLinkType() == Shortcut.DESKTOP) 412 { 413 target = System.getProperty("user.home") + FS + "Desktop" + FS + this.itsName 414 + DESKTOP_EXT; 415 this.itsFileName = target; 416 417 File source = writeShortCut(target, shortCutDef); 418 419 if (rootUser4All && create4All) 420 { 421 File dest = null; 422 File[] userHomesList = new File(FS + "home" + FS).listFiles(); 423 424 File aHomePath = null; 425 426 if (userHomesList != null) 427 { 428 for (int idx = 0; idx < userHomesList.length; idx++) 429 { 430 if (userHomesList[idx].isDirectory()) 431 { 432 433 try 434 { 435 aHomePath = userHomesList[idx]; 436 dest = new File(aHomePath.toString() + FS + "Desktop" + FS 437 + source.getName()); 438 439 copyTo(source, dest); 440 } 441 catch (Exception rex) 442 { 443 /* ignore */// most distros does not allow root to access any user 444 // home (ls -la /home/user drwx------) 445 // But try it anyway... 446 } 447 448 try 449 { 450 String[] output = new String[2]; 451 FileExecutor fe = new FileExecutor(); 452 int result = fe.executeCommand(new String[] { "/bin/chown", 453 aHomePath.getName(), aHomePath.toString()}, output); 454 if (result != 0) 455 {} 456 } 457 catch (RuntimeException rexx) 458 {} 459 } 460 } 461 } 462 } 463 } 464 else 465 { 466 File kdeHomeShareApplnk = getKdeShareApplnkFolder(this.getUserType()); 467 target = kdeHomeShareApplnk.toString() + FS + this.itsGroupName + FS + this.itsName 468 + DESKTOP_EXT; 469 this.itsFileName = target; 470 471 if (rootUser4All && !create4All) { return; } 472 writeShortCut(target, shortCutDef); 473 } 474 } 475 476 /** 477 * Copies the inFile file to outFile using cbuff as buffer. 478 * 479 * @param inFile The File to read from. 480 * @param outFile The targetFile to write to. 481 * 482 * @throws IOException If an IO Error occurs 483 */ 484 public static void copyTo(File inFile, File outFile) throws IOException 485 { 486 char[] cbuff = new char[32768]; 487 BufferedReader reader = new BufferedReader(new FileReader(inFile)); 488 BufferedWriter writer = new BufferedWriter(new FileWriter(outFile)); 489 490 int readedBytes = 0; 491 long absWrittenBytes = 0; 492 493 while ((readedBytes = reader.read(cbuff, 0, cbuff.length)) != -1) 494 { 495 writer.write(cbuff, 0, readedBytes); 496 absWrittenBytes += readedBytes; 497 } 498 499 reader.close(); 500 writer.close(); 501 } 502 503 /** 504 * Writes the given Shortcutdefinition to the given Target. 505 * Returns the written File. 506 * 507 * @param target 508 * @param shortCutDef 509 * 510 * @return the File of the written shortcut. 511 */ 512 private File writeShortCut(String target, String shortCutDef) 513 { 514 File targetPath = new File(target.toString().substring(0, 515 target.toString().lastIndexOf(File.separatorChar))); 516 517 if (!targetPath.exists()) 518 { 519 targetPath.mkdirs(); 520 this.createdDirectory = targetPath.toString(); 521 } 522 523 File targetFileName = new File( target ); 524 File backupFile = new File( targetPath + File.separator + "." + targetFileName.getName() + System.currentTimeMillis() ); 525 if( targetFileName.exists() ) 526 { 527 try 528 { 529 // create a hidden backup.file of the existing shortcut with a timestamp name. 530 copyTo( targetFileName, backupFile );// + System.e ); 531 targetFileName.delete(); 532 } 533 catch (IOException e3) 534 { 535 System.out.println("cannot create backup file " + backupFile + " of " + targetFileName );// e3.printStackTrace(); 536 } 537 } 538 FileWriter fileWriter = null; 539 540 try 541 { 542 fileWriter = new FileWriter( targetFileName ); 543 } 544 catch (IOException e1) 545 { 546 System.out.println( e1.getMessage() ); 547 } 548 549 try 550 { 551 fileWriter.write(shortCutDef); 552 } 553 catch (IOException e) 554 { 555 e.printStackTrace(); 556 } 557 558 try 559 { 560 fileWriter.close(); 561 } 562 catch (IOException e2) 563 { 564 e2.printStackTrace(); 565 } 566 567 return targetFileName; 568 } 569 570 /** 571 * Set the Commandline Arguments 572 * 573 * @see com.izforge.izpack.util.os.Shortcut#setArguments(java.lang.String) 574 */ 575 public void setArguments(String args) 576 { 577 this.itsArguments = args; 578 props.put($Arguments, args); 579 } 580 581 /** 582 * Sets the Description 583 * 584 * @see com.izforge.izpack.util.os.Shortcut#setDescription(java.lang.String) 585 */ 586 public void setDescription(String description) 587 { 588 this.itsDescription = description; 589 props.put($Comment, description); 590 } 591 592 /** 593 * Sets The Icon Path 594 * 595 * @see com.izforge.izpack.util.os.Shortcut#setIconLocation(java.lang.String, int) 596 */ 597 public void setIconLocation(String path, int index) 598 { 599 this.itsIconPath = path; 600 this.itsIconIndex = index; 601 props.put($Icon, path); 602 603 // 604 } 605 606 /** 607 * Sets the Name of this Shortcut 608 * 609 * @see com.izforge.izpack.util.os.Shortcut#setLinkName(java.lang.String) 610 */ 611 public void setLinkName(String aName) 612 { 613 this.itsName = aName; 614 props.put($Name, aName); 615 } 616 617 /** 618 * Sets the type of this Shortcut 619 * 620 * @see com.izforge.izpack.util.os.Shortcut#setLinkType(int) 621 */ 622 public void setLinkType(int aType) throws IllegalArgumentException 623 { 624 this.itsType = aType; 625 } 626 627 /** 628 * Sets the ProgramGroup 629 * 630 * @see com.izforge.izpack.util.os.Shortcut#setProgramGroup(java.lang.String) 631 */ 632 public void setProgramGroup(String aGroupName) 633 { 634 this.itsGroupName = aGroupName; 635 } 636 637 /** 638 * Sets the ShowMode 639 * 640 * @see com.izforge.izpack.util.os.Shortcut#setShowCommand(int) 641 */ 642 public void setShowCommand(int show) 643 { 644 this.itsShow = show; 645 } 646 647 /** 648 * Sets The TargetPath 649 * 650 * @see com.izforge.izpack.util.os.Shortcut#setTargetPath(java.lang.String) 651 */ 652 public void setTargetPath(String aPath) 653 { 654 this.itsTargetPath = aPath; 655 656 StringTokenizer whiteSpaceTester = new StringTokenizer( aPath ); 657 658 if( whiteSpaceTester.countTokens() > 1 ) 659 props.put( $E_QUOT,QM ); 660 661 props.put($Exec, aPath); 662 } 663 664 /** 665 * Sets the usertype. 666 * 667 * @see com.izforge.izpack.util.os.Shortcut#setUserType(int) 668 */ 669 public void setUserType(int aUserType) 670 { 671 this.itsUserType = aUserType; 672 } 673 674 /** 675 * Sets the working-directory 676 * 677 * @see com.izforge.izpack.util.os.Shortcut#setWorkingDirectory(java.lang.String) 678 */ 679 public void setWorkingDirectory(String aDirectory) 680 { 681 this.itsWorkingDirectory = aDirectory; 682 683 StringTokenizer whiteSpaceTester = new StringTokenizer( aDirectory ); 684 685 if( whiteSpaceTester.countTokens() > 1 ) 686 props.put( $P_QUOT,QM ); 687 688 props.put($Path, aDirectory); 689 } 690 691 /** 692 * Dumps the Name to console. 693 * 694 * @see java.lang.Object#toString() 695 */ 696 public String toString() 697 { 698 return this.itsName + N + template; 699 } 700 701 /** 702 * Creates the Shortcut String which will be stored as File. 703 * 704 * @return contents of the shortcut file 705 */ 706 public String replace() 707 { 708 String result = template; 709 Enumeration enumeration = props.keys(); 710 711 while (enumeration.hasMoreElements()) 712 { 713 String key = (String) enumeration.nextElement(); 714 715 result = StringTool.replace(result, key, props.getProperty(key)); 716 } 717 718 return result; 719 } 720 721 /** 722 * Test Method 723 * 724 * @param args 725 */ 726 public static void main(String[] args) 727 { 728 Unix_Shortcut aSample = new Unix_Shortcut(); 729 730 try 731 { 732 aSample.initialize(APPLICATIONS, "Start Tomcat"); 733 } 734 catch (Exception exc) 735 { 736 System.err.println("Could not init Unix_Shourtcut"); 737 } 738 739 aSample.replace(); 740 System.out.println(aSample); 741 742 File targetFileName = new File(System.getProperty("user.home") + File.separator 743 + "Start Tomcat" + DESKTOP_EXT); 744 FileWriter fileWriter = null; 745 746 try 747 { 748 fileWriter = new FileWriter(targetFileName); 749 } 750 catch (IOException e1) 751 { 752 e1.printStackTrace(); 753 } 754 755 try 756 { 757 fileWriter.write(template); 758 } 759 catch (IOException e) 760 { 761 e.printStackTrace(); 762 } 763 764 try 765 { 766 fileWriter.close(); 767 } 768 catch (IOException e2) 769 { 770 e2.printStackTrace(); 771 } 772 } 773 774 /** 775 * Sets The Encoding 776 * 777 * @see com.izforge.izpack.util.os.Shortcut#setEncoding(java.lang.String) 778 */ 779 public void setEncoding(String aEncoding) 780 { 781 props.put($Encoding, aEncoding); 782 } 783 784 /** 785 * Sets The KDE Specific subst UID property 786 * 787 * @see com.izforge.izpack.util.os.Shortcut#setKdeSubstUID(java.lang.String) 788 */ 789 public void setKdeSubstUID(String aKDESubstUID) 790 { 791 props.put($X_KDE_SubstituteUID, aKDESubstUID); 792 } 793 794 /** 795 * Sets the MimeType 796 * 797 * @see com.izforge.izpack.util.os.Shortcut#setMimetype(java.lang.String) 798 */ 799 public void setMimetype(String aMimetype) 800 { 801 props.put($MimeType, aMimetype); 802 } 803 804 /** 805 * Sets the terminal 806 * 807 * @see com.izforge.izpack.util.os.Shortcut#setTerminal(java.lang.String) 808 */ 809 public void setTerminal(String trueFalseOrNothing) 810 { 811 props.put($Terminal, trueFalseOrNothing); 812 } 813 814 /** 815 * Sets the terminal options 816 * 817 * @see com.izforge.izpack.util.os.Shortcut#setTerminalOptions(java.lang.String) 818 */ 819 public void setTerminalOptions(String someTerminalOptions) 820 { 821 props.put($Options_For_Terminal, someTerminalOptions); 822 } 823 824 /** 825 * Sets the Shortcut type (one of Application, Link or Device) 826 * 827 * @see com.izforge.izpack.util.os.Shortcut#setType(java.lang.String) 828 */ 829 public void setType(String aType) 830 { 831 props.put($Type, aType); 832 } 833 834 /** 835 * Sets the Url for type Link. Can be also a apsolute file/path 836 * 837 * @see com.izforge.izpack.util.os.Shortcut#setURL(java.lang.String) 838 */ 839 public void setURL(String anUrl) 840 { 841 props.put($URL, anUrl); 842 } 843 844 /** 845 * Gets the Usertype of the Shortcut. 846 * 847 * @see com.izforge.izpack.util.os.Shortcut#getUserType() 848 */ 849 public int getUserType() 850 { 851 return itsUserType; 852 } 853}