001/* This file is part of Vault.
002
003    Vault is free software: you can redistribute it and/or modify
004    it under the terms of the GNU Lesser General Public License as published by
005    the Free Software Foundation, either version 3 of the License, or
006    (at your option) any later version.
007
008    Vault is distributed in the hope that it will be useful,
009    but WITHOUT ANY WARRANTY; without even the implied warranty of
010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
011    GNU Lesser General Public License for more details.
012
013    You should have received a copy of the GNU Lesser General Public License
014    along with Vault.  If not, see <http://www.gnu.org/licenses/>.
015 */
016package net.milkbowl.vault.permission;
017
018import java.util.logging.Logger;
019
020import org.bukkit.OfflinePlayer;
021import org.bukkit.World;
022import org.bukkit.command.CommandSender;
023import org.bukkit.entity.Player;
024import org.bukkit.permissions.PermissionAttachment;
025import org.bukkit.permissions.PermissionAttachmentInfo;
026import org.bukkit.plugin.Plugin;
027
028/**
029 * The main Permission API - allows for group and player based permission tests
030 *
031 */
032public abstract class Permission {
033
034        protected static final Logger log = Logger.getLogger("Minecraft");
035    protected Plugin plugin = null;
036
037    /**
038     * Gets name of permission method
039     * @return Name of Permission Method
040     */
041    abstract public String getName();
042
043    /**
044     * Checks if permission method is enabled.
045     * @return Success or Failure
046     */
047    abstract public boolean isEnabled();
048    
049    /**
050     * Returns if the permission system is or attempts to be compatible with super-perms.
051     * @return True if this permission implementation works with super-perms
052     */
053    abstract public boolean hasSuperPermsCompat();
054    
055    /**
056     * @deprecated As of VaultAPI 1.4 use {@link #playerHas(String, OfflinePlayer, String)} instead.
057     */
058    @Deprecated
059    public boolean has(String world, String player, String permission) {
060        if (world == null) {
061            return playerHas((String) null, player, permission);
062        }
063        return playerHas(world, player, permission);
064    }
065
066    /**
067     * @deprecated As of VaultAPI 1.4 use {@link #playerHas(String, OfflinePlayer, String)} instead.
068     */
069    @Deprecated
070    public boolean has(World world, String player, String permission) {
071        if (world == null) {
072            return playerHas((String) null, player, permission);
073        }
074        return playerHas(world.getName(), player, permission);
075    }
076
077    /**
078     * Checks if a CommandSender has a permission node.
079     * This will return the result of bukkits, generic .hasPermission() method and is identical in all cases.
080     * This method will explicitly fail if the registered permission system does not register permissions in bukkit.
081     * 
082     * For easy checking of a commandsender
083     * @param sender to check permissions on
084     * @param permission to check for
085     * @return true if the sender has the permission
086     */
087    public boolean has(CommandSender sender, String permission) {
088        return sender.hasPermission(permission);
089    }
090
091    /**
092     * Checks if player has a permission node. (Short for playerHas(...)
093     * @param player Player Object
094     * @param permission Permission node
095     * @return Success or Failure
096     */
097    public boolean has(Player player, String permission) {
098        return player.hasPermission(permission);
099    }
100
101    /**
102     * @deprecated As of VaultAPI 1.4 use {@link #playerHas(String, OfflinePlayer, String)} instead.
103     */
104    @Deprecated
105    abstract public boolean playerHas(String world, String player, String permission);
106
107    /**
108     * @deprecated As of VaultAPI 1.4 use {@link #playerHas(String, OfflinePlayer, String)} instead.
109     */
110    @Deprecated
111    public boolean playerHas(World world, String player, String permission) {
112        if (world == null) {
113            return playerHas((String) null, player, permission);
114        }
115        return playerHas(world.getName(), player, permission);
116    }
117    
118    /**
119     * Checks if player has a permission node.
120     * Supports NULL value for World if the permission system registered supports global permissions.
121     * But May return odd values if the servers registered permission system does not have a global permission store.
122     * 
123     * @param world String world name
124     * @param player to check
125     * @param permission Permission node
126     * @return Success or Failure
127     */
128    public boolean playerHas(String world, OfflinePlayer player, String permission) {
129        if (world == null) {
130                return has((String) null, player.getName(), permission);
131        }
132        return has(world, player.getName(), permission);
133    }
134
135    /**
136     * Checks if player has a permission node.
137     * Defaults to world-specific permission check if the permission system supports it.
138     * See {@link #playerHas(String, OfflinePlayer, String)} for explicit global or world checks.
139     *  
140     * @param player Player Object
141     * @param permission Permission node
142     * @return Success or Failure
143     */
144    public boolean playerHas(Player player, String permission) {
145        return has(player, permission);
146    }
147
148    /**
149     * @deprecated As of VaultAPI 1.4 use {@link #playerAdd(String, OfflinePlayer, String)} instead.
150     * Add permission to a player.
151     * Supports NULL value for World if the permission system registered supports global permissions.
152     * But May return odd values if the servers registered permission system does not have a global permission store.
153     * 
154     * @param world World name
155     * @param player Player name
156     * @param permission Permission node
157     * @return Success or Failure
158     */
159    @Deprecated
160    abstract public boolean playerAdd(String world, String player, String permission);
161
162    /**
163     * @deprecated As of VaultAPI 1.4 use {@link #playerAdd(String, OfflinePlayer, String)} instead.
164     */
165    @Deprecated
166    public boolean playerAdd(World world, String player, String permission) {
167        if (world == null) {
168            return playerAdd((String) null, player, permission);
169        }
170        return playerAdd(world.getName(), player, permission);
171    }
172
173    /**
174     * Add permission to a player.
175     * Supports NULL value for World if the permission system registered supports global permissions.
176     * But May return odd values if the servers registered permission system does not have a global permission store.
177     * 
178     * @param world String world name
179     * @param player to add to
180     * @param permission Permission node
181     * @return Success or Failure
182     */
183    public boolean playerAdd(String world, OfflinePlayer player, String permission) {
184        if (world == null) {
185            return playerAdd((String) null, player.getName(), permission);
186        }
187        return playerAdd(world, player.getName(), permission);
188    }
189
190    /**
191     * Add permission to a player ONLY for the world the player is currently on.
192     * This is a world-specific operation, if you want to add global permission you must explicitly use NULL for the world.
193     * See {@link #playerAdd(String, OfflinePlayer, String)} for global permission use.
194     * 
195     * @param player Player Object
196     * @param permission Permission node
197     * @return Success or Failure
198     */
199    public boolean playerAdd(Player player, String permission) {
200        return playerAdd(player.getWorld().getName(), player, permission);
201    }
202 
203    /**
204     * Add transient permission to a player.
205     * This implementation can be used by any subclass which implements a "pure" superperms plugin, i.e. 
206     * one that only needs the built-in Bukkit API to add transient permissions to a player.
207     * 
208     * @param player to add to
209     * @param permission Permission node
210     * @return Success or Failure
211     */
212    public boolean playerAddTransient(OfflinePlayer player, String permission) throws UnsupportedOperationException {
213        if (player.isOnline()) {
214                return playerAddTransient((Player) player, permission);
215        }
216                throw new UnsupportedOperationException(getName() + " does not support offline player transient permissions!");
217        }
218
219    /**
220     * Add transient permission to a player.
221     * This operation adds a permission onto the player object in bukkit via Bukkit's permission interface.
222     * 
223     * @param player Player Object
224     * @param permission Permission node
225     * @return Success or Failure
226     */
227    public boolean playerAddTransient(Player player, String permission) {
228                for (PermissionAttachmentInfo paInfo : player.getEffectivePermissions()) {
229                        if (paInfo.getAttachment() != null && paInfo.getAttachment().getPlugin().equals(plugin)) {
230                                paInfo.getAttachment().setPermission(permission, true);
231                                return true;
232                        }
233                }
234
235                PermissionAttachment attach = player.addAttachment(plugin);
236                attach.setPermission(permission, true);
237
238                return true;
239    }
240
241    /**
242     * Adds a world specific transient permission to the player, may only work with some permission managers.
243     * Defaults to GLOBAL permissions for any permission system that does not support world-specific transient permissions!
244     * 
245     * @param worldName to check on
246     * @param player to add to
247     * @param permission to test
248     * @return Success or Failure
249     */
250    public boolean playerAddTransient(String worldName, OfflinePlayer player, String permission) {
251        return playerAddTransient(player, permission);
252    }
253    
254    /**
255     * Adds a world specific transient permission to the player, may only work with some permission managers.
256     * Defaults to GLOBAL permissions for any permission system that does not support world-specific transient permissions!
257     * 
258     * @param worldName to check on
259     * @param player to check
260     * @param permission to check for
261     * @return Success or Failure
262     */
263    public boolean playerAddTransient(String worldName, Player player, String permission) {
264        return playerAddTransient(player, permission);
265    }
266        
267    /**
268     * Removes a world specific transient permission from the player, may only work with some permission managers.
269     * Defaults to GLOBAL permissions for any permission system that does not support world-specific transient permissions!
270     * 
271     * @param worldName to remove for
272     * @param player to remove for
273     * @param permission to remove
274     * @return Success or Failure
275     */
276    public boolean playerRemoveTransient(String worldName, OfflinePlayer player, String permission) {
277        return playerRemoveTransient(player, permission);
278    }
279        
280    /**
281     * Removes a world specific transient permission from the player, may only work with some permission managers.
282     * Defaults to GLOBAL permissions for any permission system that does not support world-specific transient permissions!
283     * 
284     * @param worldName to check on
285     * @param player to check
286     * @param permission to check for
287     * @return Success or Failure
288     */
289    public boolean playerRemoveTransient(String worldName, Player player, String permission) {
290        return playerRemoveTransient((OfflinePlayer) player, permission);
291    }
292    
293    /**
294     * @deprecated As of VaultAPI 1.4 use {@link #playerRemove(String, OfflinePlayer, String)} instead.
295     */
296    @Deprecated
297    abstract public boolean playerRemove(String world, String player, String permission);
298
299    /**
300     * Remove permission from a player.
301     * Supports NULL value for World if the permission system registered supports global permissions.
302     * But May return odd values if the servers registered permission system does not have a global permission store.
303     * 
304     * @param world World name
305     * @param player OfflinePlayer
306     * @param permission Permission node
307     * @return Success or Failure
308     */
309    public boolean playerRemove(String world, OfflinePlayer player, String permission) {
310        if (world == null) {
311            return playerRemove((String) null, player.getName(), permission);
312        }
313        return playerRemove(world, player.getName(), permission);
314    }
315
316    /**
317     * Remove permission from a player.
318     * Supports NULL value for World if the permission system registered supports global permissions.
319     * But May return odd values if the servers registered permission system does not have a global permission store.
320     * 
321     * @param world World name
322     * @param player Player name
323     * @param permission Permission node
324     * @return Success or Failure
325     */
326    @Deprecated
327    public boolean playerRemove(World world, String player, String permission) {
328        if (world == null) {
329            return playerRemove((String) null, player, permission);
330        }
331        return playerRemove(world.getName(), player, permission);
332    }
333
334    /**
335     * Remove permission from a player.
336     * Will attempt to remove permission from the player on the player's current world.  This is NOT a global operation.
337     * 
338     * @param player Player Object
339     * @param permission Permission node
340     * @return Success or Failure
341     */
342    public boolean playerRemove(Player player, String permission) {
343        return playerRemove(player.getWorld().getName(), player, permission);
344    }
345   
346
347    /**
348     * Remove transient permission from a player.
349     * This implementation can be used by any subclass which implements a "pure" superperms plugin, i.e. 
350     * one that only needs the built-in Bukkit API to remove transient permissions from a player.  Any subclass
351     * implementing a plugin which provides its own API for this needs to override this method.
352     * 
353     * @param player OfflinePlayer
354     * @param permission Permission node
355     * @return Success or Failure
356     */
357        public boolean playerRemoveTransient(OfflinePlayer player, String permission) {
358                if (player.isOnline()) {
359                        return playerRemoveTransient((Player) player, permission);
360                } else {
361                        return false;
362                }
363        }
364    
365    /**
366     * Remove transient permission from a player.
367     * 
368     * @param player Player Object
369     * @param permission Permission node
370     * @return Success or Failure
371     */
372    public boolean playerRemoveTransient(Player player, String permission) {
373                for (PermissionAttachmentInfo paInfo : player.getEffectivePermissions()) {
374                        if (paInfo.getAttachment() != null && paInfo.getAttachment().getPlugin().equals(plugin)) {
375                                paInfo.getAttachment().unsetPermission(permission);
376                                return true;
377                        }
378                }
379                return false;
380    }
381    
382    /**
383     * Checks if group has a permission node.
384     * Supports NULL value for World if the permission system registered supports global permissions.
385     * But May return odd values if the servers registered permission system does not have a global permission store.
386     * 
387     * @param world World name
388     * @param group Group name
389     * @param permission Permission node
390     * @return Success or Failure
391     */
392    abstract public boolean groupHas(String world, String group, String permission);
393
394    /**
395     * Checks if group has a permission node.
396     * Supports NULL value for World if the permission system registered supports global permissions.
397     * But May return odd values if the servers registered permission system does not have a global permission store.
398     * 
399     * @param world World Object
400     * @param group Group name
401     * @param permission Permission node
402     * @return Success or Failure
403     */
404    public boolean groupHas(World world, String group, String permission) {
405        if (world == null) {
406            return groupHas((String) null, group, permission);
407        }
408        return groupHas(world.getName(), group, permission);
409    }
410
411    /**
412     * Add permission to a group.
413     * Supports NULL value for World if the permission system registered supports global permissions.
414     * But May return odd values if the servers registered permission system does not have a global permission store.
415     * 
416     * @param world World name
417     * @param group Group name
418     * @param permission Permission node
419     * @return Success or Failure
420     */
421    abstract public boolean groupAdd(String world, String group, String permission);
422
423    /**
424     * Add permission to a group.
425     * Supports NULL value for World if the permission system registered supports global permissions.
426     * But May return odd values if the servers registered permission system does not have a global permission store.
427     * 
428     * @param world World Object
429     * @param group Group name
430     * @param permission Permission node
431     * @return Success or Failure
432     */
433    public boolean groupAdd(World world, String group, String permission) {
434        if (world == null) {
435            return groupAdd((String) null, group, permission);
436        }
437        return groupAdd(world.getName(), group, permission);
438    }
439
440    /**
441     * Remove permission from a group.
442     * Supports NULL value for World if the permission system registered supports global permissions.
443     * But May return odd values if the servers registered permission system does not have a global permission store.
444     * 
445     * @param world World name
446     * @param group Group name
447     * @param permission Permission node
448     * @return Success or Failure
449     */
450    abstract public boolean groupRemove(String world, String group, String permission);
451
452    /**
453     * Remove permission from a group.
454     * Supports NULL value for World if the permission system registered supports global permissions.
455     * But May return odd values if the servers registered permission system does not have a global permission store.
456     * 
457     * @param world World Object
458     * @param group Group name
459     * @param permission Permission node
460     * @return Success or Failure
461     */
462    public boolean groupRemove(World world, String group, String permission) {
463        if (world == null) {
464            return groupRemove((String) null, group, permission);
465        }
466        return groupRemove(world.getName(), group, permission);
467    }
468
469    /**
470     * @deprecated As of VaultAPI 1.4 use {@link #playerInGroup(String, OfflinePlayer, String)} instead.
471     */
472    @Deprecated
473    abstract public boolean playerInGroup(String world, String player, String group);
474
475    /**
476     * @deprecated As of VaultAPI 1.4 use {@link #playerInGroup(String, OfflinePlayer, String)} instead.
477     */
478    @Deprecated
479    public boolean playerInGroup(World world, String player, String group) {
480        if (world == null) {
481            return playerInGroup((String) null, player, group);
482        }
483        return playerInGroup(world.getName(), player, group);
484    }
485    
486    /**
487     * Check if player is member of a group.
488     * Supports NULL value for World if the permission system registered supports global permissions.
489     * But May return odd values if the servers registered permission system does not have a global permission store.
490     * 
491     * @param world World Object
492     * @param player to check
493     * @param group Group name
494     * @return Success or Failure
495     */
496    public boolean playerInGroup(String world, OfflinePlayer player, String group) {
497        if (world == null) {
498            return playerInGroup((String) null, player.getName(), group);
499        }
500        return playerInGroup(world, player.getName(), group);
501    }
502
503    /**
504     * Check if player is member of a group.
505     * This method will ONLY check groups for which the player is in that are defined for the current world.
506     * This may result in odd return behaviour depending on what permission system has been registered.
507     * 
508     * @param player Player Object
509     * @param group Group name
510     * @return Success or Failure
511     */
512    public boolean playerInGroup(Player player, String group) {
513        return playerInGroup(player.getWorld().getName(), player, group);
514    }
515
516    /**
517     * @deprecated As of VaultAPI 1.4 use {@link #playerAddGroup(String, OfflinePlayer, String)} instead.
518     */
519    @Deprecated
520    abstract public boolean playerAddGroup(String world, String player, String group);
521
522    /**
523     * @deprecated As of VaultAPI 1.4 use {@link #playerAddGroup(String, OfflinePlayer, String)} instead.
524     */
525    @Deprecated
526    public boolean playerAddGroup(World world, String player, String group) {
527        if (world == null) {
528            return playerAddGroup((String) null, player, group);
529        }
530        return playerAddGroup(world.getName(), player, group);
531    }
532
533    /**
534     * Add player to a group.
535     * Supports NULL value for World if the permission system registered supports global permissions.
536     * But May return odd values if the servers registered permission system does not have a global permission store.
537     * 
538     * @param world String world name
539     * @param player to add
540     * @param group Group name
541     * @return Success or Failure
542     */
543    public boolean playerAddGroup(String world, OfflinePlayer player, String group) {
544        if (world == null) {
545            return playerAddGroup((String) null, player.getName(), group);
546        }
547        return playerAddGroup(world, player.getName(), group);
548    }
549    
550    /**
551     * Add player to a group.
552     * This will add a player to the group on the current World.  This may return odd results if the permission system
553     * being used on the server does not support world-specific groups, or if the group being added to is a global group.
554     * 
555     * @param player Player Object
556     * @param group Group name
557     * @return Success or Failure
558     */
559    public boolean playerAddGroup(Player player, String group) {
560        return playerAddGroup(player.getWorld().getName(), player, group);
561    }
562
563    /**
564     * @deprecated As of VaultAPI 1.4 use {@link #playerRemoveGroup(String, OfflinePlayer, String)} instead.
565     */
566    @Deprecated
567    abstract public boolean playerRemoveGroup(String world, String player, String group);
568
569    /**
570     * @deprecated As of VaultAPI 1.4 use {@link #playerRemoveGroup(String, OfflinePlayer, String)} instead.
571     */
572    @Deprecated
573    public boolean playerRemoveGroup(World world, String player, String group) {
574        if (world == null) {
575            return playerRemoveGroup((String) null, player, group);
576        }
577        return playerRemoveGroup(world.getName(), player, group);
578    }
579    
580    /**
581     * Remove player from a group.
582     * Supports NULL value for World if the permission system registered supports global permissions.
583     * But May return odd values if the servers registered permission system does not have a global permission store.
584     * 
585     * @param world World Object
586     * @param player to remove
587     * @param group Group name
588     * @return Success or Failure
589     */
590    public boolean playerRemoveGroup(String world, OfflinePlayer player, String group) {
591        if (world == null) {
592            return playerRemoveGroup((String) null, player.getName(), group);
593        }
594        return playerRemoveGroup(world, player.getName(), group);
595    }
596
597    /**
598     * Remove player from a group.
599     * This will add a player to the group on the current World.  This may return odd results if the permission system
600     * being used on the server does not support world-specific groups, or if the group being added to is a global group.
601     * 
602     * @param player Player Object
603     * @param group Group name
604     * @return Success or Failure
605     */
606    public boolean playerRemoveGroup(Player player, String group) {
607        return playerRemoveGroup(player.getWorld().getName(), player, group);
608    }
609
610    /**
611     * @deprecated As of VaultAPI 1.4 use {@link #getPlayerGroups(String, OfflinePlayer)} instead.
612     */
613    @Deprecated
614    abstract public String[] getPlayerGroups(String world, String player);
615
616    /**
617     * @deprecated As of VaultAPI 1.4 use {@link #getPlayerGroups(String, OfflinePlayer)} instead.
618     */
619    @Deprecated
620    public String[] getPlayerGroups(World world, String player) {
621        if (world == null) {
622            return getPlayerGroups((String) null, player);
623        }
624        return getPlayerGroups(world.getName(), player);
625    }
626    
627    /**
628     * Gets the list of groups that this player has
629     * Supports NULL value for World if the permission system registered supports global permissions.
630     * But May return odd values if the servers registered permission system does not have a global permission store.
631     * 
632     * @param world String world name
633     * @param player OfflinePlayer
634     * @return Array of groups
635     */
636    public String[] getPlayerGroups(String world, OfflinePlayer player) {
637        return getPlayerGroups(world, player.getName());
638    }
639
640    /**
641     * Returns a list of world-specific groups that this player is currently in. May return unexpected results if
642     * you are looking for global groups, or if the registered permission system does not support world-specific groups.
643     * See {@link #getPlayerGroups(String, OfflinePlayer)} for better control of World-specific or global groups.
644     * 
645     * @param player Player Object
646     * @return Array of groups
647     */
648    public String[] getPlayerGroups(Player player) {
649        return getPlayerGroups(player.getWorld().getName(), player);
650    }
651
652    /**
653     * @deprecated As of VaultAPI 1.4 use {@link #getPrimaryGroup(String, OfflinePlayer)} instead.
654     */
655    @Deprecated
656    abstract public String getPrimaryGroup(String world, String player);
657
658    /**
659     * @deprecated As of VaultAPI 1.4 use {@link #getPrimaryGroup(String, OfflinePlayer)} instead.
660     */
661    @Deprecated
662    public String getPrimaryGroup(World world, String player) {
663        if (world == null) {
664            return getPrimaryGroup((String) null, player);
665        }
666        return getPrimaryGroup(world.getName(), player);
667    }
668    
669    /**
670     * Gets players primary group
671     * Supports NULL value for World if the permission system registered supports global permissions.
672     * But May return odd values if the servers registered permission system does not have a global permission store.
673     * 
674     * @param world String world name
675     * @param player to get from
676     * @return Players primary group
677     */
678    public String getPrimaryGroup(String world, OfflinePlayer player) {
679        return getPrimaryGroup(world, player.getName());
680    }
681
682    /**
683     * Get players primary group.
684     * Defaults to the players current world, so may return only world-specific groups.
685     * In most cases {@link #getPrimaryGroup(String, OfflinePlayer)} is preferable.
686     * 
687     * @param player Player Object
688     * @return Players primary group
689     */
690    public String getPrimaryGroup(Player player) {
691        return getPrimaryGroup(player.getWorld().getName(), player);
692    }
693    
694    /**
695     * Returns a list of all known groups
696     * @return an Array of String of all groups
697     */
698    abstract public String[] getGroups();
699    
700    /**
701     * Returns true if the given implementation supports groups.
702     * @return true if the implementation supports groups
703     */
704    abstract public boolean hasGroupSupport();
705}