| 1 | /* | 
 
 
 
 
 | 2 | * unlink.js | 
 
 
 
 
 | 3 | * | 
 
 
 
 
 | 4 | * $Id: unlink.js,v cd9a9ac85727 2013/09/20 08:43:04 keithmarshall $ | 
 
 
 
 
 | 5 | * | 
 
 
 
 
 | 6 | * Invoke the Windows Scripting Host to remove specified files, typically | 
 
 
 
 
 | 7 | * from the user's or all users' start menu or desktop directories. | 
 
 
 
 
 | 8 | * | 
 
 
 
 
 | 9 | * Usage: | 
 
 
 
 
 | 10 | *   cscript -nologo unlink.js [--option ...] file ... | 
 
 
 
 
 | 11 | * | 
 
 
 
 
 | 12 | * Options: | 
 
 
 
 
 | 13 | *   --all-users | 
 
 
 
 
 | 14 | *              references to desktop or start menu files apply | 
 
 
 
 
 | 15 | *              to the directories serving all users | 
 
 
 
 
 | 16 | * | 
 
 
 
 
 | 17 | *   --desktop  remove files from the user's desktop directory, (or | 
 
 
 
 
 | 18 | *              from all users' desktop directory, with --all-users) | 
 
 
 
 
 | 19 | * | 
 
 
 
 
 | 20 | *   --start-menu | 
 
 
 
 
 | 21 | *              remove files from the user's start menu directory, (or | 
 
 
 
 
 | 22 | *              from all users' start menu directory, with --all-users) | 
 
 
 
 
 | 23 | * | 
 
 
 
 
 | 24 | *   --if-linked=target_path | 
 
 
 
 
 | 25 | *              do not remove any matched file which is not a shortcut | 
 
 
 
 
 | 26 | *              (.lnk or .url) referring to the specified target path; | 
 
 
 
 
 | 27 | *              when this option is specified, any specified file name | 
 
 
 
 
 | 28 | *              which does not already have a .lnk or .url extension | 
 
 
 
 
 | 29 | *              will have .lnk appended, before seeking any match | 
 
 
 
 
 | 30 | * | 
 
 
 
 
 | 31 | *   --force    override read-only attributes when removing files. | 
 
 
 
 
 | 32 | * | 
 
 
 
 
 | 33 | * Parameters: | 
 
 
 
 
 | 34 | *   file       the path name for a file to be removed; if --desktop | 
 
 
 
 
 | 35 | *              or --start-menu is specified, it should be a relative | 
 
 
 
 
 | 36 | *              path name, which will then be resolved relative to the | 
 
 
 
 
 | 37 | *              appropriate system directory path. | 
 
 
 
 
 | 38 | * | 
 
 
 
 
 | 39 | * | 
 
 
 
 
 | 40 | * This file is a component of mingw-get. | 
 
 
 
 
 | 41 | * | 
 
 
 
 
 | 42 | * Written by Keith Marshall <keithmarshall@users.sourceforge.net> | 
 
 
 
 
 | 43 | * Copyright (C) 2012, 2013, MinGW.org Project | 
 
 
 
 
 | 44 | * | 
 
 
 
 
 | 45 | * | 
 
 
 
 
 | 46 | * Permission is hereby granted, free of charge, to any person obtaining a | 
 
 
 
 
 | 47 | * copy of this software and associated documentation files (the "Software"), | 
 
 
 
 
 | 48 | * to deal in the Software without restriction, including without limitation | 
 
 
 
 
 | 49 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 
 
 
 
 
 | 50 | * and/or sell copies of the Software, and to permit persons to whom the | 
 
 
 
 
 | 51 | * Software is furnished to do so, subject to the following conditions: | 
 
 
 
 
 | 52 | * | 
 
 
 
 
 | 53 | * The above copyright notice and this permission notice shall be included | 
 
 
 
 
 | 54 | * in all copies or substantial portions of the Software. | 
 
 
 
 
 | 55 | * | 
 
 
 
 
 | 56 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | 
 
 
 
 
 | 57 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
 
 
 
 
 | 58 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | 
 
 
 
 
 | 59 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
 
 
 
 
 | 60 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | 
 
 
 
 
 | 61 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 
 
 
 
 
 | 62 | * DEALINGS IN THE SOFTWARE. | 
 
 
 
 
 | 63 | * | 
 
 
 
 
 | 64 | */ | 
 
 
 
 
 | 65 | var cmdName = WScript.ScriptName; | 
 
 
 
 
 | 66 | var FileSystem = WScript.CreateObject("Scripting.FileSystemObject"); | 
 
 
 
 
 | 67 | var WinShell = WScript.CreateObject("WScript.Shell"); | 
 
 
 
 
 | 68 |  | 
 
 
 
 
 | 69 | /* Strip ".js" suffix from command name. | 
 
 
 
 
 | 70 | */ | 
 
 
 
 
 | 71 | var i = cmdName.lastIndexOf( ".js" ); | 
 
 
 
 
 | 72 | if( (i > 0) &&  (cmdName.substr( i ) == ".js") ) | 
 
 
 
 
 | 73 | cmdName = cmdName.substr( 0, i ); | 
 
 
 
 
 | 74 |  | 
 
 
 
 
 | 75 | /* Specify the keywords which identify command line options. | 
 
 
 
 
 | 76 | */ | 
 
 
 
 
 | 77 | var options = Array( | 
 
 
 
 
 | 78 | /* | 
 
 
 
 
 | 79 | *  Option              Effect | 
 
 
 
 
 | 80 | *  -------------       ------------------------- | 
 
 
 
 
 | 81 | */ | 
 
 
 
 
 | 82 | "all-users",     /* Resolve file path names in all-users domain... */ | 
 
 
 
 
 | 83 | "start-menu",    /* ...relative to user's or all-users' start menu... */ | 
 
 
 
 
 | 84 | "desktop",       /* ...or desktop directories. */ | 
 
 
 
 
 | 85 | "if-linked",     /* Only delete shortcuts with specified target path */ | 
 
 
 
 
 | 86 | "force"          /* Forcibly override read-only attribute */ | 
 
 
 
 
 | 87 | ); | 
 
 
 
 
 | 88 |  | 
 
 
 
 
 | 89 | /* Initialise all options as "unassigned". | 
 
 
 
 
 | 90 | */ | 
 
 
 
 
 | 91 | var unassigned = "+++unassigned+++"; | 
 
 
 
 
 | 92 | var assigned = Array( options.length ); | 
 
 
 
 
 | 93 | for( i = 0; i < assigned.length; i++ ) | 
 
 
 
 
 | 94 | assigned[i] = unassigned; | 
 
 
 
 
 | 95 |  | 
 
 
 
 
 | 96 | /* The "complain" function provides a mechanism for writing | 
 
 
 
 
 | 97 | * diagnostic messages to stderr, and optionally aborting the | 
 
 
 
 
 | 98 | * calling script. | 
 
 
 
 
 | 99 | */ | 
 
 
 
 
 | 100 | function complain( condition, message ) | 
 
 
 
 
 | 101 | { | 
 
 
 
 
 | 102 | WScript.StdErr.WriteLine( cmdName + ": " + message ); | 
 
 
 
 
 | 103 | if( condition < 0 ) | 
 
 
 
 
 | 104 | WScript.Quit( -condition ); | 
 
 
 
 
 | 105 | return condition; | 
 
 
 
 
 | 106 | } | 
 
 
 
 
 | 107 |  | 
 
 
 
 
 | 108 | /* Parse the command line, to identify any specified options. | 
 
 
 
 
 | 109 | */ | 
 
 
 
 
 | 110 | var chklink = ""; | 
 
 
 
 
 | 111 | var argv = WScript.Arguments; | 
 
 
 
 
 | 112 | for( i = 0; i < argv.length; i++ ) | 
 
 
 
 
 | 113 | { | 
 
 
 
 
 | 114 | if( argv( i ).indexOf( "--" ) == 0 ) | 
 
 
 
 
 | 115 | { | 
 
 
 
 
 | 116 | /* Handle arguments specifying options... | 
 
 
 
 
 | 117 | */ | 
 
 
 
 
 | 118 | var optind; | 
 
 
 
 
 | 119 | var matched = 0; | 
 
 
 
 
 | 120 | var optname = argv( i ).substr( 2 ); | 
 
 
 
 
 | 121 | var optarg = ""; | 
 
 
 
 
 | 122 | for( var k = 0; k < options.length; k++ ) | 
 
 
 
 
 | 123 | { | 
 
 
 
 
 | 124 | /* Try to match each defined option in turn... | 
 
 
 
 
 | 125 | */ | 
 
 
 
 
 | 126 | var argind = optname.indexOf( "=" ); | 
 
 
 
 
 | 127 | if( argind > 0 ) | 
 
 
 
 
 | 128 | { | 
 
 
 
 
 | 129 | optarg = optname.substr( argind + 1 ); | 
 
 
 
 
 | 130 | optname = optname.substr( 0, argind ); | 
 
 
 
 
 | 131 | } | 
 
 
 
 
 | 132 |  | 
 
 
 
 
 | 133 | if( optname == options[k] ) | 
 
 
 
 
 | 134 | { | 
 
 
 
 
 | 135 | /* A exact (complete) match trumps any possible abbreviation... | 
 
 
 
 
 | 136 | */ | 
 
 
 
 
 | 137 | matched = 1; | 
 
 
 
 
 | 138 | assigned[optind = k] = optname; | 
 
 
 
 
 | 139 | k = options.length; | 
 
 
 
 
 | 140 | } | 
 
 
 
 
 | 141 |  | 
 
 
 
 
 | 142 | else if( options[k].indexOf( optname ) == 0 ) | 
 
 
 
 
 | 143 | { | 
 
 
 
 
 | 144 | /* Otherwise abbreviations are allowed, but must uniquely | 
 
 
 
 
 | 145 | * identify only one defined option name... | 
 
 
 
 
 | 146 | */ | 
 
 
 
 
 | 147 | if( matched++ > 0 ) | 
 
 
 
 
 | 148 | complain( -2, "option '" + argv( i ) + "' is ambiguous" ); | 
 
 
 
 
 | 149 | assigned[optind = k] = options[k]; | 
 
 
 
 
 | 150 | } | 
 
 
 
 
 | 151 | } | 
 
 
 
 
 | 152 | if( matched == 0 ) | 
 
 
 
 
 | 153 | /* | 
 
 
 
 
 | 154 | * Bail out, if no match identified. | 
 
 
 
 
 | 155 | */ | 
 
 
 
 
 | 156 | complain( -2, "option '" + argv( i ) + "' is undefined" ); | 
 
 
 
 
 | 157 |  | 
 
 
 
 
 | 158 | if( assigned[optind] == "if-linked" ) | 
 
 
 
 
 | 159 | chklink = optarg; | 
 
 
 
 
 | 160 | } | 
 
 
 
 
 | 161 | } | 
 
 
 
 
 | 162 |  | 
 
 
 
 
 | 163 | /* Establish prefix for resolving paths relative to desktop | 
 
 
 
 
 | 164 | * or start menu directories, and handle the --force option. | 
 
 
 
 
 | 165 | */ | 
 
 
 
 
 | 166 | var prefix = ""; | 
 
 
 
 
 | 167 | var allusers = false; | 
 
 
 
 
 | 168 | var force = false; | 
 
 
 
 
 | 169 | for( i = 0; i < options.length; i++ ) | 
 
 
 
 
 | 170 | { | 
 
 
 
 
 | 171 | switch( assigned[i] ) | 
 
 
 
 
 | 172 | { | 
 
 
 
 
 | 173 | case "force": | 
 
 
 
 
 | 174 | force = true; | 
 
 
 
 
 | 175 | break; | 
 
 
 
 
 | 176 |  | 
 
 
 
 
 | 177 | case "all-users": | 
 
 
 
 
 | 178 | allusers = true; | 
 
 
 
 
 | 179 | break; | 
 
 
 
 
 | 180 |  | 
 
 
 
 
 | 181 | case "start-menu": | 
 
 
 
 
 | 182 | prefix = WinShell.SpecialFolders( allusers ? "AllUsersStartMenu" | 
 
 
 
 
 | 183 | : "StartMenu" | 
 
 
 
 
 | 184 | ) + "\\"; | 
 
 
 
 
 | 185 | break; | 
 
 
 
 
 | 186 |  | 
 
 
 
 
 | 187 | case "desktop": | 
 
 
 
 
 | 188 | if( prefix != "" ) | 
 
 
 
 
 | 189 | complain( -2, "options '--start-menu' and '--desktop' are incompatible" ); | 
 
 
 
 
 | 190 | prefix = WinShell.SpecialFolders( allusers ? "AllUsersDesktop" | 
 
 
 
 
 | 191 | : "Desktop" | 
 
 
 
 
 | 192 | ) + "\\"; | 
 
 
 
 
 | 193 | } | 
 
 
 
 
 | 194 | } | 
 
 
 
 
 | 195 |  | 
 
 
 
 
 | 196 | /* Parse the command line again, to process path name arguments, | 
 
 
 
 
 | 197 | * and delete the specified files. | 
 
 
 
 
 | 198 | */ | 
 
 
 
 
 | 199 | for( i = 0; i < argv.length; i++ ) | 
 
 
 
 
 | 200 | { | 
 
 
 
 
 | 201 | if( argv( i ).indexOf( "--" ) != 0 ) | 
 
 
 
 
 | 202 | { | 
 
 
 
 
 | 203 | /* Not an option argument, so assume it's a path name. | 
 
 
 
 
 | 204 | */ | 
 
 
 
 
 | 205 | var filename = prefix + argv( i ); | 
 
 
 
 
 | 206 | if( chklink != "" ) | 
 
 
 
 
 | 207 | { | 
 
 
 
 
 | 208 | /* The "--if-linked" option is in effect, and a viable | 
 
 
 
 
 | 209 | * target path has been defined.  The file to be deleted | 
 
 
 
 
 | 210 | * MUST be a shortcut file, (i.e. it MUST bear a ".lnk" or | 
 
 
 
 
 | 211 | * ".url" extension); supply ".lnk" as default, if this is | 
 
 
 
 
 | 212 | * not so. | 
 
 
 
 
 | 213 | */ | 
 
 
 
 
 | 214 | var l = filename.length - 4; | 
 
 
 
 
 | 215 | var suffix = (l > 0) ? filename.substr( l ) : 0; | 
 
 
 
 
 | 216 | if( (suffix != ".lnk") && (suffix != ".url") ) | 
 
 
 
 
 | 217 | filename += ".lnk"; | 
 
 
 
 
 | 218 | } | 
 
 
 
 
 | 219 | if( FileSystem.FileExists( filename ) ) | 
 
 
 
 
 | 220 | { | 
 
 
 
 
 | 221 | /* The requisite file DOES exist... | 
 
 
 
 
 | 222 | */ | 
 
 
 
 
 | 223 | if( chklink != "" ) | 
 
 
 
 
 | 224 | { | 
 
 
 
 
 | 225 | /* ...but when "--if-linked is in effect, we must verify that | 
 
 
 
 
 | 226 | * the link target is matched (case-insensitively), before... | 
 
 
 
 
 | 227 | */ | 
 
 
 
 
 | 228 | var ref = WinShell.CreateShortcut( filename ); | 
 
 
 
 
 | 229 | var chk = WinShell.CreateShortcut( filename ); chk.TargetPath = chklink; | 
 
 
 
 
 | 230 | if( ref.TargetPath.toLowerCase() == chk.TargetPath.toLowerCase() ) | 
 
 
 
 
 | 231 | /* | 
 
 
 
 
 | 232 | * ...we may proceed with deletion. | 
 
 
 
 
 | 233 | */ | 
 
 
 
 
 | 234 | FileSystem.DeleteFile( filename, force ); | 
 
 
 
 
 | 235 | } | 
 
 
 
 
 | 236 | else | 
 
 
 
 
 | 237 | /* When "--if-linked" is NOT in effect, we may simply | 
 
 
 
 
 | 238 | * proceed with deletion, without further ado. | 
 
 
 
 
 | 239 | */ | 
 
 
 
 
 | 240 | FileSystem.DeleteFile( filename, force ); | 
 
 
 
 
 | 241 | } | 
 
 
 
 
 | 242 | } | 
 
 
 
 
 | 243 | } | 
 
 
 
 
 | 244 |  | 
 
 
 
 
 | 245 | /* $RCSfile: unlink.js,v $: end of file */ |