001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.tag;
020
021import lucee.runtime.exp.ApplicationException;
022import lucee.runtime.exp.PageException;
023import lucee.runtime.exp.SecurityException;
024import lucee.runtime.ext.tag.TagImpl;
025import lucee.runtime.op.Caster;
026import lucee.runtime.registry.RegistryEntry;
027import lucee.runtime.registry.RegistryQuery;
028import lucee.runtime.security.SecurityManager;
029import lucee.runtime.type.KeyImpl;
030import lucee.runtime.type.QueryImpl;
031import lucee.runtime.type.util.KeyConstants;
032
033/**
034* Reads, writes, and deletes keys and values in the system registry. The cfregistry tag is supported 
035*   on all platforms, including Linux, Solaris, and HP-UX.
036*
037*
038*
039**/
040public final class Registry extends TagImpl {
041    
042    private static final short ACTION_GET_ALL=0;
043    private static final short ACTION_GET=1;
044    private static final short ACTION_SET=2;
045    private static final short ACTION_DELETE=3;
046    
047    
048
049        /** Value data to set. If you omit this attribute, cfregistry creates default value, as follows:
050        ** 
051        ** string: creates an empty string: "" 
052        ** dWord: creates a value of 0 (zero) */
053        private String value;
054
055        /** action to the registry */
056        private short action=-1;
057
058        /** Sorts query column data (case-insensitive). Sorts on Entry, Type, and Value columns as text. Specify a combination of columns from query output, in a comma-delimited list. For example: 
059        ** sort = "value desc, entry asc"
060        ** 
061        ** asc: ascending (a to z) sort order 
062        ** desc: descending (z to a) sort order */
063        private String sort;
064
065        /** string: return string values 
066        ** dWord: return DWord values 
067        ** key: return keys 
068        ** any: return keys and values */
069        private short type=RegistryEntry.TYPE_ANY;
070
071        /** Name of a registry branch. */
072        private String branch;
073
074        /** Registry value to access. */
075        private String entry;
076
077        /** Variable into which to put value. */
078        private String variable;
079
080        /** Name of record set to contain returned keys and values. */
081        private String name;
082        
083
084        @Override
085        public void release()   {
086                super.release();
087                value=null;
088                action=-1;
089                sort=null;
090                type=RegistryEntry.TYPE_ANY;
091                branch=null;
092                entry=null;
093                variable=null;
094                name=null;
095        }
096
097        /** set the value value
098        *  Value data to set. If you omit this attribute, cfregistry creates default value, as follows:
099        * 
100        * string: creates an empty string: "" 
101        * dWord: creates a value of 0 (zero)
102        * @param value value to set
103        **/
104        public void setValue(String value)      {
105                this.value=value;
106        }
107
108        /** set the value action
109        *  action to the registry
110        * @param action value to set
111         * @throws ApplicationException
112        **/
113        public void setAction(String action) throws ApplicationException        {
114            action=action.toLowerCase().trim();
115            if(action.equals("getall")) this.action=ACTION_GET_ALL;
116            else if(action.equals("get")) this.action=ACTION_GET;
117            else if(action.equals("set")) this.action=ACTION_SET;
118            else if(action.equals("delete")) this.action=ACTION_DELETE;
119            else throw new ApplicationException("attribute action of the tag registry has an invalid value ["+action+"], valid values are [getAll, get, set, delete]");
120        }
121
122        /** set the value sort
123        *  Sorts query column data (case-insensitive). Sorts on Entry, Type, and Value columns as text. Specify a combination of columns from query output, in a comma-delimited list. For example: 
124        * sort = "value desc, entry asc"
125        * 
126        * asc: ascending (a to z) sort order 
127        * desc: descending (z to a) sort order
128        * @param sort value to set
129        **/
130        public void setSort(String sort)        {
131                this.sort=sort;
132        }
133
134        /** set the value type
135        *  string: return string values 
136        * dWord: return DWord values 
137        * key: return keys 
138        * any: return keys and values
139        * @param type value to set
140         * @throws ApplicationException
141        **/
142        public void setType(String type) throws ApplicationException    {
143            type=type.toLowerCase().trim();
144            if(type.equals("string")) this.type=RegistryEntry.TYPE_STRING;
145            else if(type.equals("dword")) this.type=RegistryEntry.TYPE_DWORD;
146            else if(type.equals("key")) this.type=RegistryEntry.TYPE_KEY;
147            else if(type.equals("any")) this.type=RegistryEntry.TYPE_ANY;
148            else throw new ApplicationException("attribute type of the tag registry has an invalid value ["+type+"], valid values are [string, dword]");
149        }
150
151        /** set the value branch
152        *  Name of a registry branch.
153        * @param branch value to set
154        **/
155        public void setBranch(String branch)    {
156                this.branch=branch;
157        }
158
159        /** set the value entry
160        *  Registry value to access.
161        * @param entry value to set
162        **/
163        public void setEntry(String entry)      {
164                this.entry=entry;
165        }
166
167        /** set the value variable
168        *  Variable into which to put value.
169        * @param variable value to set
170        **/
171        public void setVariable(String variable)        {
172                this.variable=variable;
173        }
174
175        /** set the value name
176        *  Name of record set to contain returned keys and values.
177        * @param name value to set
178        **/
179        public void setName(String name)        {
180                this.name=name;
181        }
182
183
184        @Override
185        public int doStartTag() throws PageException    {
186            if(pageContext.getConfig().getSecurityManager().getAccess(SecurityManager.TYPE_TAG_REGISTRY)==SecurityManager.VALUE_NO) 
187                        throw new SecurityException("can't access tag [registry]","access is prohibited by security manager");
188                
189            
190            if(action==ACTION_GET) doGet();
191            else if(action==ACTION_GET_ALL) doGetAll();
192            else if(action==ACTION_SET) doSet();
193            else if(action==ACTION_DELETE) doDelete();
194            
195            
196            
197                return SKIP_BODY;
198        }
199
200        /**
201         * @throws PageException
202     * 
203     */
204    private void doDelete() throws PageException {
205        try {
206            RegistryQuery.deleteValue(branch,entry);
207        }
208        catch (Exception e) {
209            throw Caster.toPageException(e);
210        } 
211    }
212
213    /**
214     * @throws PageException
215     * 
216     */
217    private void doSet() throws PageException {
218        if(entry==null)throw new ApplicationException("attribute entry is required for tag registry, when action is [set]");
219        if(type==RegistryEntry.TYPE_ANY)type=RegistryEntry.TYPE_STRING;
220        if(value==null) {
221            if(type==RegistryEntry.TYPE_DWORD)value="0";
222            else value="";
223        }
224        
225        try {
226            RegistryQuery.setValue(branch,entry,type,value);
227        } 
228        catch (Exception e) {
229            throw Caster.toPageException(e);
230        } 
231        
232    }
233
234    /**
235     * @throws PageException
236     * 
237     */
238    private void doGetAll() throws PageException {
239        if(name==null)throw new ApplicationException("attribute name is required for tag registry, when action is [getAll]");
240        
241        
242        try {
243            RegistryEntry[] entries = RegistryQuery.getValues(branch,type);
244            if(entries!=null) {
245                lucee.runtime.type.Query qry=new QueryImpl(
246                        new String[]{"entry","type","value"},
247                        new String[]{"VARCHAR","VARCHAR","OTHER"},
248                        entries.length,"query");
249                for(int i=0;i<entries.length;i++) {
250                    RegistryEntry e = entries[i];
251                    int row=i+1;
252                    qry.setAt(KeyConstants._entry,row,e.getKey());
253                    qry.setAt(KeyConstants._type,row,RegistryEntry.toCFStringType(e.getType()));
254                    qry.setAt(KeyConstants._value,row,e.getValue());
255                }
256                
257
258                        // sort
259                        if(sort!=null) {
260                                String[] arr=sort.toLowerCase().split(",");
261                                for(int i=arr.length-1;i>=0;i--) {
262                                        String[] col=arr[i].trim().split("\\s+");
263                                        if(col.length==1)qry.sort(KeyImpl.init(col[0].trim()));
264                                        else if(col.length==2) {
265                                                String order=col[1].toLowerCase().trim();
266                                                if(order.equals("asc"))
267                                                    qry.sort(KeyImpl.init(col[0]),lucee.runtime.type.Query.ORDER_ASC);
268                                                else if(order.equals("desc"))
269                                                    qry.sort(KeyImpl.init(col[0]),lucee.runtime.type.Query.ORDER_DESC);
270                                                else 
271                                                        throw new ApplicationException("invalid order type ["+col[1]+"]");
272                                        }
273                                }               
274                        }
275                
276                
277                
278                
279                
280                
281                
282                pageContext.setVariable(name,qry);
283            }
284        } 
285        catch (Exception e) {
286            throw Caster.toPageException(e);
287        } 
288        
289    }
290
291    /**
292     * @throws PageException
293     * 
294     */
295    private void doGet() throws PageException {
296        // "HKEY_LOCAL_MACHINE\\SOFTWARE\\Google\\NavClient","installtime"
297        if(entry==null)throw new ApplicationException("attribute entry is required for tag registry, when action is [get]");
298        if(variable==null)throw new ApplicationException("attribute variable is required for tag registry, when action is [get]");
299        //if(type==-1)throw new ApplicationException("attribute type is required for tag registry, when action is [get]");
300        
301        
302        try {
303            RegistryEntry re = RegistryQuery.getValue(branch,entry,type);
304            if(re!=null)pageContext.setVariable(variable,re.getValue());
305        } 
306        catch (Exception e) {
307            throw Caster.toPageException(e);
308        } 
309        
310    }
311
312    @Override
313        public int doEndTag()   {
314                return EVAL_PAGE;
315        }
316
317}