#! /usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2009-2013 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
# Jiri Popelka <jpopelka@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

from gi.repository import GObject
import sys
sys.modules['gobject'] = GObject

import argparse
import dbus
import os

from firewall.client import FirewallClient
from firewall.errors import *
from firewall.functions import splitArgs, joinArgs

def __print(msg=None):
    if msg and not a.quiet:
        print(msg)

def __print_and_exit(msg=None, exit_code=0):
    FAIL = '\033[91m'
    OK =   '\033[92m'
    END =  '\033[00m'
    if exit_code != 0:
        __print(FAIL + msg + END)
    else:
        __print(msg)
        #__print(OK + msg + END)
    sys.exit(exit_code)

def __fail(msg=None):
    __print_and_exit(msg, 2)

def __print_if_verbose(msg=None):
    if msg and a.verbose:
        print(msg)

def __usage():
    print """
Usage: firewall-cmd [OPTIONS...]

General Options
  -h, --help           Prints a short help text and exists
  -V, --version        Print the version string of firewalld
  -q, --quiet          Do not print status messages

Status Options
  --state              Return and print firewalld state
  --reload             Reload firewall and keep state information
  --complete-reload    Reload firewall and loose state information

Permanent Options
  --permanent          Set an option permanently
                       Usable for options maked with [P]

Zone Options
  --get-default-zone   Print default zone for connections and interfaces
  --set-default-zone=<zone>
                       Set default zone
  --get-active-zones   Print currently active zones
  --get-zones          Print predefined zones [P]
  --get-services       Print predefined services [P]
  --get-icmptypes      Print predefined icmptypes [P]
  --get-zone-of-interface=<interface>
                       Print name of the zone the interface is bound to [P]
  --get-zone-of-source=<source>[/<mask>]
                       Print name of the zone the source[/mask] is bound to [P]
  --list-all-zones     List everything added for or enabled in all zones [P]
  --zone=<zone>        Use this zone to set or query options, else default zone
                       Usable for options maked with [Z]

Options to Adapt and Query Zones
  --list-all           List everything added for or enabled in a zone [P] [Z]
  --list-services      List services added for a zone [P] [Z]
  --timeout=<seconds>  Enable an option for seconds only
                       Usable for options maked with [T]
  --add-service=<service>
                       Add a service for a zone [P] [Z] [T]
  --remove-service=<service>
                       Remove a service from a zone [P] [Z]
  --query-service=<service>
                       Return whether service has been added for a zone [P] [Z]
  --list-ports         List ports added for a zone [P] [Z]
  --add-port=<portid>[-<portid>]/<protocol>
                       Add the port for a zone [P] [Z] [T]
  --remove-port=<portid>[-<portid>]/<protocol>
                       Remove the port from a zone [P] [Z]
  --query-port=<portid>[-<portid>]/<protocol>
                       Return whether the port has been added for zone [P] [Z]
  --list-icmp-blocks   List Internet ICMP type blocks added for a zone [P] [Z]
  --add-icmp-block=<icmptype>
                       Add an ICMP block for a zone [P] [Z] [T]
  --remove-icmp-block=<icmptype>
                       Remove the ICMP block from a zone [P] [Z]
  --query-icmp-block=<icmptype>
                       Return whether an ICMP block has been added for a zone
                       [P] [Z]
  --list-forward-ports List IPv4 forward ports added for a zone [P] [Z]
  --add-forward-port=port=<portid>[-<portid>]:proto=<protocol>[:toport=<portid>[-<portid>]][:toaddr=<address>[/<mask>]]
                       Add the IPv4 forward port for a zone [P] [Z] [T]
  --remove-forward-port=port=<portid>[-<portid>]:proto=<protocol>[:toport=<portid>[-<portid>]][:toaddr=<address>[/<mask>]]
                       Remove the IPv4 forward port from a zone [P] [Z]


  --query-forward-port=port=<portid>[-<portid>]:proto=<protocol>[:toport=<portid>[-<portid>]][:toaddr=<address>[/<mask>]]
                       Return whether the IPv4 forward port has been added for
                       a zone [P] [Z]
  --add-masquerade     Enable IPv4 masquerade for a zone [P] [Z] [T]
  --remove-masquerade  Disable IPv4 masquerade for a zone [P] [Z]
  --query-masquerade   Return whether IPv4 masquerading has been enabled for a
                       zone [P] [Z]
  --list-rich-rules    List rich language rules added for a zone [P] [Z]
  --add-rich-rule=<rule>
                       Add rich language rule 'rule' for a zone [P] [Z] [T]
  --remove-rich-rule=<rule>
                       Remove rich language rule 'rule' from a zone [P] [Z]
  --query-rich-rule=<rule>
                       Return whether a rich language rule 'rule' has been
                       added for a zone [P] [Z]

Options to Handle Bindings of Interfaces
  --list-interfaces    List interfaces that are bound to a zone [P] [Z]
  --add-interface=<interface>
                       Bind the <interface> to a zone [P] [Z]
  --change-interface=<interface>
                       Change zone the <interface> is bound to [Z]
  --query-interface=<interface>
                       Query whether <interface> is bound to a zone [P] [Z]
  --remove-interface=<interface>
                       Remove binding of <interface> from a zone [P] [Z]

Options to Handle Bindings of Sources
  --list-sources       List sources that are bound to a zone [P] [Z]
  --add-source=<source>[/<mask>]
                       Bind <source>[/<mask>] to a zone [P] [Z]
  --change-source=<source>[/<mask>]
                       Change zone the <source>[/<mask>] is bound to [Z]
  --query-source=<source>[/<mask>]
                       Query whether <source>[/<mask>] is bound to a zone
                       [P] [Z]
  --remove-source=<source>[/<mask>]
                       Remove binding of <source>[/<mask>] from a zone [P] [Z]

Direct Options
  --direct             First option for all direct options
  --get-all-chains
                       Get all chains [P]
  --get-chains {ipv4|ipv6|eb} <table>
                       Get all chains added to the table [P]
  --add-chain {ipv4|ipv6|eb} <table> <chain>
                       Add a new chain to the table [P]
  --remove-chain {ipv4|ipv6|eb} <table> <chain>
                       Remove the chain from the table [P]
  --query-chain {ipv4|ipv6|eb} <table> <chain>
                       Return whether the chain has been added to the table [P]
  --get-all-rules
                       Get all rules [P]
  --get-rules {ipv4|ipv6|eb} <table> <chain>
                       Get all rules added to chain in table [P]
  --add-rule {ipv4|ipv6|eb} <table> <chain> <priority> <arg>...
                       Add rule to chain in table [P]
  --remove-rule {ipv4|ipv6|eb} <table> <chain> <priority> <arg>...
                       Remove rule with priority from chain in table [P]
  --query-rule {ipv4|ipv6|eb} <table> <chain> <priority> <arg>...
                       Return whether a rule with priority has been added to
                       chain in table [P]
  --passthrough {ipv4|ipv6|eb} <arg>...
                       Pass a command through
  --get-all-passthroughs
                       Get all passthrough rules [P only]
  --get-passthroughs {ipv4|ipv6|eb} <arg>...
                       Get passthrough rules [P only]
  --add-passthrough {ipv4|ipv6|eb} <arg>...
                       Add a new passthrough rule [P only]
  --remove-passthrough {ipv4|ipv6|eb} <arg>...
                       Remove a passthrough rule [P only]
  --query-passthrough {ipv4|ipv6|eb} <arg>...
                       Return whether the passthrough rule has been added
                       [P only]

Lockdown Options
  --lockdown-on        Enable lockdown.
  --lockdown-off       Disable lockdown.
  --query-lockdown     Query whether lockdown is enabled

Lockdown Whitelist Options
  --list-lockdown-whitelist-commands
                       List all command lines that are on the whitelist [P]
  --add-lockdown-whitelist-command=<command>
                       Add the command to the whitelist [P]
  --remove-lockdown-whitelist-command=<command>
                       Remove the command from the whitelist [P]
  --query-lockdown-whitelist-command=<command>
                       Query whether the command is on the whitelist [P]
  --list-lockdown-whitelist-contexts
                       List all contexts that are on the whitelist [P]
  --add-lockdown-whitelist-context=<context>
                       Add the context context to the whitelist [P]
  --remove-lockdown-whitelist-context=<context>
                       Remove the context from the whitelist [P]
  --query-lockdown-whitelist-context=<context>
                       Query whether the context is on the whitelist [P]
  --list-lockdown-whitelist-uids
                       List all user ids that are on the whitelist [P]
  --add-lockdown-whitelist-uid=<uid>
                       Add the user id uid to the whitelist [P]
  --remove-lockdown-whitelist-uid=<uid>
                       Remove the user id uid from the whitelist [P]
  --query-lockdown-whitelist-uid=<uid>
                       Query whether the user id uid is on the whitelist [P]
  --list-lockdown-whitelist-users
                       List all user names that are on the whitelist [P]
  --add-lockdown-whitelist-user=<user>
                       Add the user name user to the whitelist [P]
  --remove-lockdown-whitelist-user=<user>
                       Remove the user name user from the whitelist [P]
  --query-lockdown-whitelist-user=<user>
                       Query whether the user name user is on the whitelist [P]

Panic Options
  --panic-on           Enable panic mode
  --panic-off          Disable panic mode
  --query-panic        Query whether panic mode is enabled
"""

def __parse_port(value):
    try:
        (port, proto) = value.split("/")
    except Exception as e:
        __fail("bad port (most likely missing protocol), correct syntax is portid[-portid]/protocol")
    return (port, proto)

def __parse_forward_port(value):
    port = None
    protocol = None
    toport = None
    toaddr = None
    args = value.split(":")
    for arg in args:
        try:
            (opt,val) = arg.split("=")
            if opt == "port":
                port = val
            elif opt == "proto":
                protocol = val
            elif opt == "toport":
                toport = val
            elif opt == "toaddr":
                toaddr = val
        except:
            __fail("invalid forward port arg '%s'" % (arg))
    if not port:
        __fail("missing port")
    if not protocol:
        __fail("missing protocol")
    if not (toport or toaddr):
        __fail("missing destination")
    return (port, protocol, toport, toaddr)

def _check_ipv(value):
    if value != "ipv4" and value != "ipv6" and value != "eb":
        __fail("invalid argument: %s (choose from 'ipv4', 'ipv6', 'eb')" % value)
    return value

def __print_all(zone, interfaces, sources, services, ports, masquerade, forward_ports, icmp_blocks, rules):
    attributes = []
    if zone == fw.getDefaultZone():
        attributes.append("default")
    if interfaces:
        attributes.append("active")
    if attributes:
        zone = zone + " (%s)" % ", ".join(attributes)
    __print(zone)
    __print("  interfaces: " + " ".join(interfaces))
    __print("  sources: " + " ".join(sources))
    __print("  services: " + " ".join(services))
    __print("  ports: " + " ".join(["%s/%s" % (port[0], port[1]) for port in ports]))
    __print("  masquerade: %s" % ("yes" if masquerade else "no"))
    __print("  forward-ports: " + "\n\t".join(["port=%s:proto=%s:toport=%s:toaddr=%s" % (port, protocol, toport, toaddr) for (port, protocol, toport, toaddr) in forward_ports]))
    __print("  icmp-blocks: " + " ".join(icmp_blocks))
    __print("  rich rules: \n\t" + "\n\t".join(rules))

def __list_all(fw, zone):
    interfaces = fw.getInterfaces(zone)
    sources = fw.getSources(zone)
    services = fw.getServices(zone)
    ports = fw.getPorts(zone)
    masquerade = fw.queryMasquerade(zone)
    forward_ports = fw.getForwardPorts(zone)
    icmp_blocks = fw.getIcmpBlocks(zone)
    rules = fw.getRichRules(zone)
    __print_all(zone, interfaces, sources, services, ports, masquerade, forward_ports, icmp_blocks, rules)

def __list_all_permanent(fw_settings, zone):
    interfaces = fw_settings.getInterfaces()
    sources = fw_settings.getSources()
    services = fw_settings.getServices()
    ports = fw_settings.getPorts()
    masquerade = fw_settings.getMasquerade()
    forward_ports = fw_settings.getForwardPorts()
    icmp_blocks = fw_settings.getIcmpBlocks()
    rules = fw_settings.getRichRules()
    __print_all(zone, interfaces, sources, services, ports, masquerade, forward_ports, icmp_blocks, rules)

def __print_query_result(value):
    if value:
        __print_and_exit("yes")
    else:
        __print_and_exit("no", 1)

parser = argparse.ArgumentParser(usage="see firewall-cmd man page",
                                 add_help=False)

parser_group_output = parser.add_mutually_exclusive_group()
parser_group_output.add_argument("-v", "--verbose", action="store_true")
parser_group_output.add_argument("-q", "--quiet", action="store_true")

parser_group_standalone = parser.add_mutually_exclusive_group()
parser_group_standalone.add_argument("-h", "--help",
                                     action="store_true")
parser_group_standalone.add_argument("-V", "--version", action="store_true")
parser_group_standalone.add_argument("--state", action="store_true")
parser_group_standalone.add_argument("--reload", action="store_true")
parser_group_standalone.add_argument("--complete-reload", action="store_true")
parser_group_standalone.add_argument("--panic-on", action="store_true")
parser_group_standalone.add_argument("--panic-off", action="store_true")
parser_group_standalone.add_argument("--query-panic", action="store_true")
parser_group_standalone.add_argument("--lockdown-on", action="store_true")
parser_group_standalone.add_argument("--lockdown-off", action="store_true")
parser_group_standalone.add_argument("--query-lockdown", action="store_true")

parser_group_standalone.add_argument("--get-default-zone", action="store_true")
parser_group_standalone.add_argument("--set-default-zone", metavar="<zone>")
parser_group_standalone.add_argument("--get-zones", action="store_true")
parser_group_standalone.add_argument("--get-services", action="store_true")
parser_group_standalone.add_argument("--get-icmptypes", action="store_true")
parser_group_standalone.add_argument("--get-active-zones", action="store_true")
parser_group_standalone.add_argument("--get-zone-of-interface", metavar="<iface>")
parser_group_standalone.add_argument("--get-zone-of-source", metavar="<source>")
parser_group_standalone.add_argument("--list-all-zones", action="store_true")

parser_group_lockdown_whitelist = parser.add_mutually_exclusive_group()
parser_group_lockdown_whitelist.add_argument("--list-lockdown-whitelist-commands", action="store_true")
parser_group_lockdown_whitelist.add_argument("--add-lockdown-whitelist-command", metavar="<command>")
parser_group_lockdown_whitelist.add_argument("--remove-lockdown-whitelist-command", metavar="<command>")
parser_group_lockdown_whitelist.add_argument("--query-lockdown-whitelist-command", metavar="<command>")

parser_group_lockdown_whitelist.add_argument("--list-lockdown-whitelist-contexts", action="store_true")
parser_group_lockdown_whitelist.add_argument("--add-lockdown-whitelist-context", metavar="<context>")
parser_group_lockdown_whitelist.add_argument("--remove-lockdown-whitelist-context", metavar="<context>")
parser_group_lockdown_whitelist.add_argument("--query-lockdown-whitelist-context", metavar="<context>")

parser_group_lockdown_whitelist.add_argument("--list-lockdown-whitelist-uids", action="store_true")
parser_group_lockdown_whitelist.add_argument("--add-lockdown-whitelist-uid", metavar="<uid>", type=int)
parser_group_lockdown_whitelist.add_argument("--remove-lockdown-whitelist-uid", metavar="<uid>", type=int)
parser_group_lockdown_whitelist.add_argument("--query-lockdown-whitelist-uid", metavar="<uid>", type=int)

parser_group_lockdown_whitelist.add_argument("--list-lockdown-whitelist-users", action="store_true")
parser_group_lockdown_whitelist.add_argument("--add-lockdown-whitelist-user", metavar="<user>")
parser_group_lockdown_whitelist.add_argument("--remove-lockdown-whitelist-user", metavar="<user>")
parser_group_lockdown_whitelist.add_argument("--query-lockdown-whitelist-user", metavar="<user>")

parser.add_argument("--permanent", action="store_true")
parser.add_argument("--zone", default="", metavar="<zone>")
parser.add_argument("--timeout", default=0, type=int, metavar="<seconds>")

parser_group_zone = parser.add_mutually_exclusive_group()
parser_group_zone.add_argument("--add-interface", metavar="<iface>")
parser_group_zone.add_argument("--remove-interface", metavar="<iface>")
parser_group_zone.add_argument("--query-interface", metavar="<iface>")
parser_group_zone.add_argument("--change-interface", "--change-zone", metavar="<iface>")
parser_group_zone.add_argument("--list-interfaces", action="store_true")
parser_group_zone.add_argument("--add-source", metavar="<source>")
parser_group_zone.add_argument("--remove-source", metavar="<source>")
parser_group_zone.add_argument("--query-source", metavar="<source>")
parser_group_zone.add_argument("--change-source", metavar="<source>")
parser_group_zone.add_argument("--list-sources", action="store_true")
parser_group_zone.add_argument("--add-rich-rule", metavar="<rule>", action='append')
parser_group_zone.add_argument("--remove-rich-rule", metavar="<rule>", action='append')
parser_group_zone.add_argument("--query-rich-rule", metavar="<rule>")
parser_group_zone.add_argument("--add-service", metavar="<service>", action='append')
parser_group_zone.add_argument("--remove-service", metavar="<zone>", action='append')
parser_group_zone.add_argument("--query-service", metavar="<zone>")
parser_group_zone.add_argument("--add-port", metavar="<port>", action='append')
parser_group_zone.add_argument("--remove-port", metavar="<port>", action='append')
parser_group_zone.add_argument("--query-port", metavar="<port>")
parser_group_zone.add_argument("--add-masquerade", action="store_true")
parser_group_zone.add_argument("--remove-masquerade", action="store_true")
parser_group_zone.add_argument("--query-masquerade", action="store_true")
parser_group_zone.add_argument("--add-icmp-block", metavar="<icmptype>", action='append')
parser_group_zone.add_argument("--remove-icmp-block", metavar="<icmptype>", action='append')
parser_group_zone.add_argument("--query-icmp-block", metavar="<icmptype>")
parser_group_zone.add_argument("--add-forward-port", metavar="<port>", action='append')
parser_group_zone.add_argument("--remove-forward-port", metavar="<port>", action='append')
parser_group_zone.add_argument("--query-forward-port", metavar="<port>")
parser_group_zone.add_argument("--list-rich-rules", action="store_true")
parser_group_zone.add_argument("--list-services", action="store_true")
parser_group_zone.add_argument("--list-ports", action="store_true")
parser_group_zone.add_argument("--list-icmp-blocks", action="store_true")
parser_group_zone.add_argument("--list-forward-ports", action="store_true")
parser_group_zone.add_argument("--list-all", action="store_true")

parser.add_argument("--direct", action="store_true")

parser_direct = parser.add_mutually_exclusive_group()
parser_direct.add_argument("--passthrough", nargs=argparse.REMAINDER,
                    metavar=("{ ipv4 | ipv6 | eb }", "<args>"))
parser_direct.add_argument("--add-passthrough", nargs=argparse.REMAINDER,
                    metavar=("{ ipv4 | ipv6 | eb }", "<args>"))
parser_direct.add_argument("--remove-passthrough", nargs=argparse.REMAINDER,
                    metavar=("{ ipv4 | ipv6 | eb }", "<args>"))
parser_direct.add_argument("--query-passthrough", nargs=argparse.REMAINDER,
                    metavar=("{ ipv4 | ipv6 | eb }", "<args>"))
parser_direct.add_argument("--get-passthroughs", nargs=1,
                    metavar=("{ ipv4 | ipv6 | eb }", "<args>"))
parser_direct.add_argument("--get-all-passthroughs", action="store_true")
parser_direct.add_argument("--add-chain", nargs=3,
                    metavar=("{ ipv4 | ipv6 | eb }", "<table>", "<chain>"))
parser_direct.add_argument("--remove-chain", nargs=3,
                        metavar=("{ ipv4 | ipv6 | eb }", "<table>", "<chain>"))
parser_direct.add_argument("--query-chain", nargs=3,
                        metavar=("{ ipv4 | ipv6 | eb }", "<table>", "<chain>"))
parser_direct.add_argument("--get-all-chains", action="store_true")
parser_direct.add_argument("--get-chains", nargs=2,
                        metavar=("{ ipv4 | ipv6 | eb }", "<table>"))
parser_direct.add_argument("--add-rule", nargs=argparse.REMAINDER,
                        metavar=("{ ipv4 | ipv6 | eb }", "<table> <chain> <priority> <args>"))
parser_direct.add_argument("--remove-rule", nargs=argparse.REMAINDER,
                        metavar=("{ ipv4 | ipv6 | eb }", "<table> <chain> <args>"))
parser_direct.add_argument("--query-rule", nargs=argparse.REMAINDER,
                        metavar=("{ ipv4 | ipv6 | eb }", "<table> <chain> <args>"))
parser_direct.add_argument("--get-rules", nargs=3,
                        metavar=("{ ipv4 | ipv6 | eb }", "<table>", "<chain>"))
parser_direct.add_argument("--get-all-rules", action="store_true")

a = parser.parse_args()

options_standalone = a.help or a.version or \
    a.state or a.reload or a.complete_reload or \
    a.panic_on or a.panic_off or a.query_panic or \
    a.lockdown_on or a.lockdown_off or a.query_lockdown or \
    a.get_default_zone or a.set_default_zone or \
    a.get_active_zones

options_lockdown_whitelist = \
    a.list_lockdown_whitelist_commands or a.add_lockdown_whitelist_command or \
    a.remove_lockdown_whitelist_command or \
    a.query_lockdown_whitelist_command or \
    a.list_lockdown_whitelist_contexts or a.add_lockdown_whitelist_context or \
    a.remove_lockdown_whitelist_context or \
    a.query_lockdown_whitelist_context or \
    a.list_lockdown_whitelist_uids or a.add_lockdown_whitelist_uid or \
    a.remove_lockdown_whitelist_uid or \
    a.query_lockdown_whitelist_uid or \
    a.list_lockdown_whitelist_users or a.add_lockdown_whitelist_user or \
    a.remove_lockdown_whitelist_user or \
    a.query_lockdown_whitelist_user

options_config = a.get_zones or a.get_services or a.get_icmptypes or \
                 options_lockdown_whitelist or a.list_all_zones or \
                 a.get_zone_of_interface or a.get_zone_of_source

options_zone_action_action = \
    a.add_service or a.remove_service or a.query_service or \
    a.add_port or a.remove_port or a.query_port or \
    a.add_icmp_block or a.remove_icmp_block or a.query_icmp_block or \
    a.add_forward_port or a.remove_forward_port or a.query_forward_port

options_zone_interfaces_sources = \
    a.list_interfaces or a.change_interface or \
    a.add_interface or a.remove_interface or a.query_interface or \
    a.list_sources or a.change_source or \
    a.add_source or a.remove_source or a.query_source

options_zone_adapt_query = \
    a.add_rich_rule or a.remove_rich_rule or a.query_rich_rule or \
    a.add_masquerade or a.remove_masquerade or a.query_masquerade or \
    a.list_services or a.list_ports or a.list_icmp_blocks or \
    a.list_forward_ports or a.list_rich_rules or a.list_all

options_zone_ops = options_zone_interfaces_sources or \
               options_zone_action_action or options_zone_adapt_query

options_zone = a.zone or a.timeout or options_zone_ops

options_permanent = a.permanent or options_config or a.zone or options_zone_ops

options_direct = a.passthrough or \
           a.add_chain or a.remove_chain or a.query_chain or \
           a.get_chains or a.get_all_chains or \
           a.add_rule or a.remove_rule or a.query_rule or \
           a.get_rules or a.get_all_rules

options_direct_permanent = \
           a.add_passthrough or a.remove_passthrough or a.query_passthrough or \
           a.get_passthroughs or a.get_all_passthroughs

# these are supposed to only write out some output
options_list_get = a.help or a.version or a.list_all or a.list_all_zones or \
 a.list_lockdown_whitelist_commands or a.list_lockdown_whitelist_contexts or \
 a.list_lockdown_whitelist_uids or a.list_lockdown_whitelist_users or \
 a.list_services or a.list_ports or a.list_icmp_blocks or a.list_forward_ports \
 or a.list_rich_rules or a.list_interfaces or a.list_sources or \
 a.get_default_zone or a.get_active_zones or a.get_zone_of_interface or \
 a.get_zone_of_source or a.get_zones or a.get_services or a.get_icmptypes

# Check various impossible combinations of options

if not (options_standalone or options_zone or \
        options_permanent or options_direct or options_direct_permanent):
    __fail(parser.format_usage() + "No option specified.")

if options_standalone and (options_zone or options_permanent or \
                               options_direct or options_direct_permanent):
    __fail(parser.format_usage() +
           "Can't use stand-alone options with other options.")

if (options_direct or options_direct_permanent) and (options_zone):
    __fail(parser.format_usage() +
           "Can't use 'direct' options with other options.")

if (a.direct and not (options_direct or options_direct_permanent)) or \
        ((options_direct or options_direct_permanent) and not a.direct):
    __fail(parser.format_usage() +
           "Wrong usage of 'direct' options.")

if options_direct_permanent and not a.permanent:
    __fail(parser.format_usage() +
           "Option can be used only with --permanent.")

if options_config and options_zone:
    __fail(parser.format_usage() +
           "Wrong usage of --get-zones | --get-services | --get-icmptypes.")

if a.timeout and not (a.add_service or a.add_port or a.add_icmp_block or \
                          a.add_forward_port or a.add_masquerade or \
                          a.add_rich_rule):
    __fail(parser.format_usage() + "Wrong --timeout usage")

if a.permanent:
    if a.timeout != 0:
        __fail(parser.format_usage() +
               "Can't specify timeout for permanent action.")
    if options_config and not a.zone:
        pass
    elif options_permanent:
        pass
    else:
        __fail(parser.format_usage() + "Wrong --permanent usage.")

if a.quiet and options_list_get:
    # it makes no sense to use --quiet with these options
    a.quiet = False
    __fail("-q/--quiet can't be used with this option(s)")

if a.help:
    __usage()
    sys.exit(0)

zone = a.zone
try:
    fw = FirewallClient()
    if fw.connected == False:
        if a.state:
            __print_and_exit ("not running", NOT_RUNNING)
        else:
            __print_and_exit ("FirewallD is not running", NOT_RUNNING)

    if options_zone_ops and not zone:
        default = fw.getDefaultZone()
        __print_if_verbose("No zone specified, using default zone, i.e. '%s'" % default)
        active = list(fw.getActiveZones().keys())
        if active and default not in active:
            __print ("""You're performing an operation over default zone ('%s'),
but your connections/interfaces are in zone '%s' (see --get-active-zones)
You most likely need to use --zone=%s option.\n""" % (default, ",".join(active), active[0]))

    if a.permanent:
        if a.get_zones:
            zones = fw.config().listZones()
            l = [fw.config().getZone(z).get_property("name") for z in zones]
            __print_and_exit(" ".join(sorted(l)))
        elif a.get_services:
            services = fw.config().listServices()
            l = [fw.config().getService(s).get_property("name") for s in services]
            __print_and_exit(" ".join(sorted(l)))
        elif a.get_icmptypes:
            icmptypes = fw.config().listIcmpTypes()
            l = [fw.config().getIcmpType(i).get_property("name") for i in icmptypes]
            __print_and_exit(" ".join(sorted(l)))

        # lockdown whitelist

        elif options_lockdown_whitelist:
            whitelist = fw.config().policies().getLockdownWhitelist()
                
            # commands
            if a.list_lockdown_whitelist_commands:
                l = whitelist.getCommands()
                __print_and_exit("\n".join(l))
            elif a.add_lockdown_whitelist_command:
                whitelist.addCommand(a.add_lockdown_whitelist_command)
            elif a.remove_lockdown_whitelist_command:
                whitelist.removeCommand(a.remove_lockdown_whitelist_command)
            elif a.query_lockdown_whitelist_command:
                __print_query_result(whitelist.queryCommand( \
                                     a.query_lockdown_whitelist_command))

            # contexts
            elif a.list_lockdown_whitelist_contexts:
                l = whitelist.getContexts()
                __print_and_exit("\n".join(l))
            elif a.add_lockdown_whitelist_context:
                whitelist.addContext(a.add_lockdown_whitelist_context) 
            elif a.remove_lockdown_whitelist_context:
                whitelist.removeContext(a.remove_lockdown_whitelist_context)
            elif a.query_lockdown_whitelist_context:
                __print_query_result(whitelist.queryContext( \
                                     a.query_lockdown_whitelist_context))

            # uids
            elif a.list_lockdown_whitelist_uids:
                l = whitelist.getUids()
                __print_and_exit(" ".join(map(str, l)))
            elif a.add_lockdown_whitelist_uid:
                whitelist.addUid(a.add_lockdown_whitelist_uid)
            elif a.remove_lockdown_whitelist_uid:
                whitelist.removeUid(a.remove_lockdown_whitelist_uid)
            elif a.query_lockdown_whitelist_uid:
                __print_query_result(whitelist.queryUid( \
                                     a.query_lockdown_whitelist_uid))

            # users
            elif a.list_lockdown_whitelist_users:
                l = whitelist.getUsers()
                __print_and_exit("\n".join(l))
            elif a.add_lockdown_whitelist_user:
                whitelist.addUser(a.add_lockdown_whitelist_user) 
            elif a.remove_lockdown_whitelist_user:
                whitelist.removeUser(a.remove_lockdown_whitelist_user)
            elif a.query_lockdown_whitelist_user:
                __print_query_result(whitelist.queryUser( \
                                     a.query_lockdown_whitelist_user))

            # apply whitelist changes
            fw.config().policies().setLockdownWhitelist(whitelist)

        elif options_direct or options_direct_permanent:
            settings = fw.config().direct().getSettings()

            if a.passthrough:
                if len (a.passthrough) < 2:
                    __fail("usage: --permanent --direct --passthrough { ipv4 | ipv6 | eb } <args>")
                __print(settings.addPassthrough(_check_ipv(a.passthrough[0]),
                                                           a.passthrough[1:]))

            if a.add_passthrough:
                if len (a.add_passthrough) < 2:
                    __fail("usage: --permanent --direct --add-passthrough { ipv4 | ipv6 | eb } <args>")
                __print(settings.addPassthrough(
                    _check_ipv(a.add_passthrough[0]), a.add_passthrough[1:]))

            elif a.remove_passthrough:
                if len (a.remove_passthrough) < 2:
                    __fail("usage: --permanent --direct --remove-passthrough { ipv4 | ipv6 | eb } <args>")
                settings.removePassthrough(_check_ipv(a.remove_passthrough[0]),
                                                      a.remove_passthrough[1:])
            elif a.query_passthrough:
                if len (a.query_passthrough) < 2:
                    __fail("usage: --permanent --direct --query-passthrough { ipv4 | ipv6 | eb } <args>")
                __print_query_result(
                    settings.queryPassthrough(
                        _check_ipv(a.query_passthrough[0]),
                                   a.query_passthrough[1:]))
                sys.exit(0)
            elif a.get_passthroughs:
                rules = settings.getPassthroughs(
                    _check_ipv(a.get_passthroughs[0]))
                for rule in rules:
                    __print(joinArgs(rule))
                sys.exit(0)
            elif a.get_all_passthroughs:
                for (ipv,rule) in settings.getAllPassthroughs():
                    __print("%s %s" % (ipv, joinArgs(rule)))
                sys.exit(0)

            elif a.add_chain:
                settings.addChain(_check_ipv(a.add_chain[0]),
                                  a.add_chain[1], a.add_chain[2])
            elif a.remove_chain:
                settings.removeChain(_check_ipv(a.remove_chain[0]),
                                     a.remove_chain[1], a.remove_chain[2])
            elif a.query_chain:
                __print_query_result(
                    settings.queryChain(_check_ipv(a.query_chain[0]),
                                        a.query_chain[1], a.query_chain[2]))
                sys.exit(0)
            elif a.get_chains:
                __print_and_exit(
                    " ".join(settings.getChains(_check_ipv(a.get_chains[0]),
                                                           a.get_chains[1])))
                sys.exit(0)
            elif a.get_all_chains:
                chains = settings.getAllChains()
                for (ipv, table, chain) in chains:
                    __print("%s %s %s" % (ipv, table, chain))
                sys.exit(0)
            elif a.add_rule:
                if len (a.add_rule) < 5:
                    __fail("usage: --permanent --direct --add-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>")
                try:
                    priority = int(a.add_rule[3])
                except ValueError:
                    __fail("wrong priority\nusage: --permanent --direct --add-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>")
                settings.addRule(_check_ipv(a.add_rule[0]), a.add_rule[1],
                                 a.add_rule[2], priority, a.add_rule[4:])
            elif a.remove_rule:
                if len (a.remove_rule) < 5:
                    __fail("usage: --permanent --direct --remove-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>")
                try:
                    priority = int(a.remove_rule[3])
                except ValueError:
                    __fail("usage: --permanent --direct --remove-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>")
                settings.removeRule(_check_ipv(a.remove_rule[0]),
                                    a.remove_rule[1], a.remove_rule[2],
                                    priority, a.remove_rule[4:])
            elif a.query_rule:
                if len (a.query_rule) < 5:
                    __fail("usage: --permanent --direct --query-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>")
                try:
                    priority = int(a.query_rule[3])
                except ValueError:
                    __fail("usage: --permanent --direct --query-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>")
                __print_query_result(
                    settings.queryRule(_check_ipv(a.query_rule[0]),
                                       a.query_rule[1], a.query_rule[2],
                                       priority, a.query_rule[4:]))
                sys.exit(0)
            elif a.get_rules:
                rules = settings.getRules(_check_ipv(a.get_rules[0]),
                                          a.get_rules[1], a.get_rules[2])
                for (priority, rule) in rules:
                    __print("%d %s" % (priority, joinArgs(rule)))
                sys.exit(0)
            elif a.get_all_rules:
                rules = settings.getAllRules()
                for (ipv, table, chain, priority, rule) in rules:
                    __print("%s %s %s %d %s" % (ipv, table, chain, priority,
                                                joinArgs(rule)))
                sys.exit(0)

            fw.config().direct().update(settings)

        else:
            if zone == "":
                zone = fw.getDefaultZone()
            fw_zone = fw.config().getZoneByName(zone)
            fw_settings = fw_zone.getSettings()

            # interface
            if a.list_interfaces:
                l = fw_settings.getInterfaces()
                __print_and_exit(" ".join(l))
            elif a.get_zone_of_interface:
                zone = fw.config().getZoneOfInterface(a.get_zone_of_interface)
                if zone:
                    __print_and_exit(zone)
                else:
                    __print_and_exit("no zone", 2)
            elif a.change_interface:
                old_zone_name = fw.config().getZoneOfInterface(a.change_interface)
                if old_zone_name != zone:
                    if old_zone_name:
                        old_zone_obj = fw.config().getZoneByName(old_zone_name)
                        old_zone_settings = old_zone_obj.getSettings()
                        old_zone_settings.removeInterface(a.change_interface) # remove from old
                        old_zone_obj.update(old_zone_settings)
                    fw_settings.addInterface(a.change_interface)              # add to new
            elif a.add_interface:
                fw_settings.addInterface(a.add_interface)
            elif a.remove_interface:
                fw_settings.removeInterface(a.remove_interface)
            elif a.query_interface:
                __print_query_result(fw_settings.queryInterface(a.query_interface))

            # source
            if a.list_sources:
                sources = fw_settings.getSources()
                __print_and_exit(" ".join(sources))
            elif a.get_zone_of_source:
                zone = fw.config().getZoneOfSource(a.get_zone_of_source)
                if zone:
                    __print_and_exit(zone)
                else:
                    __print_and_exit("no zone", 2)
            elif a.change_source:
                old_zone_name = fw.config().getZoneOfSource(a.change_source)
                old_zone_obj = fw.config().getZoneByName(old_zone_name)
                old_zone_settings = old_zone_obj.getSettings()
                old_zone_settings.removeSource(a.change_source)  # remove from old
                old_zone_obj.update(old_zone_settings)
                fw_settings.addSource(a.change_source)           # add to new
            elif a.add_source:
                fw_settings.addSource(a.add_source)
            elif a.remove_source:
                fw_settings.removeSource(a.remove_source)
            elif a.query_source:
                __print_query_result(fw_settings.querySource(a.query_source))

            # rich rules
            if a.list_rich_rules:
                l = fw_settings.getRichRules()
                __print_and_exit("\n".join(l))
            elif a.add_rich_rule:
                for s in a.add_rich_rule:
                    fw_settings.addRichRule(s)
            elif a.remove_rich_rule:
                for s in a.remove_rich_rule:
                    fw_settings.removeRichRule(s)
            elif a.query_rich_rule:
                __print_query_result(fw_settings.queryRichRule(a.query_rich_rule))

            # service
            if a.list_services:
                l = fw_settings.getServices()
                __print_and_exit(" ".join(l))
            elif a.add_service:
                for s in a.add_service:
                    fw_settings.addService(s)
            elif a.remove_service:
                for s in a.remove_service:
                    fw_settings.removeService(s)
            elif a.query_service:
                __print_query_result(fw_settings.queryService(a.query_service))

            # port
            elif a.list_ports:
                l = fw_settings.getPorts()
                __print_and_exit(" ".join(["%s/%s" % (port[0], port[1]) for port in l]))
            elif a.add_port:
                for port_proto in a.add_port:
                    (port, proto) = __parse_port(port_proto)
                    fw_settings.addPort(port, proto)
            elif a.remove_port:
                for port_proto in a.remove_port:
                    (port, proto) = __parse_port(port_proto)
                    fw_settings.removePort(port, proto)
            elif a.query_port:
                (port, proto) = __parse_port(a.query_port)
                __print_query_result(fw_settings.queryPort(port, proto))

            # masquerade
            elif a.add_masquerade:
                fw_settings.setMasquerade(True)
            elif a.remove_masquerade:
                fw_settings.setMasquerade(False)
            elif a.query_masquerade:
                __print_query_result(fw_settings.getMasquerade())

            # forward port
            elif a.list_forward_ports:
                l = fw_settings.getForwardPorts()
                __print_and_exit("\n".join(["port=%s:proto=%s:toport=%s:toaddr=%s" % (port, protocol, toport, toaddr) for (port, protocol, toport, toaddr) in l]))
            elif a.add_forward_port:
                for fp in a.add_forward_port:
                    (port, protocol, toport, toaddr) = __parse_forward_port(fp)
                    fw_settings.addForwardPort(port, protocol, toport, toaddr)
            elif a.remove_forward_port:
                for fp in a.remove_forward_port:
                    (port, protocol, toport, toaddr) = __parse_forward_port(fp)
                    fw_settings.removeForwardPort(port, protocol, toport, toaddr)
            elif a.query_forward_port:
                (port, protocol, toport, toaddr) = __parse_forward_port(a.query_forward_port)
                __print_query_result(fw_settings.queryForwardPort(port, protocol, toport, toaddr))

            # block icmp
            elif a.list_icmp_blocks:
                l = fw_settings.getIcmpBlocks()
                __print_and_exit(" ".join(l))
            elif a.add_icmp_block:
                for ib in a.add_icmp_block: 
                    fw_settings.addIcmpBlock(ib)
            elif a.remove_icmp_block:
                for ib in a.remove_icmp_block:
                    fw_settings.removeIcmpBlock(ib)
            elif a.query_icmp_block:
                __print_query_result(fw_settings.queryIcmpBlock(a.query_icmp_block))

            # list all zone settings
            elif a.list_all:
                __list_all_permanent(fw_settings, zone if zone else fw.getDefaultZone())
                sys.exit(0)

            # list everything
            elif a.list_all_zones:
                zones = fw.config().listZones()
                names = [fw.config().getZone(z).get_property("name") for z in zones]
                for zone in sorted(names):
                    fw_zone = fw.config().getZoneByName(zone)
                    fw_settings = fw_zone.getSettings()
                    __list_all_permanent(fw_settings, zone)
                    __print("")
                sys.exit(0)

            fw_zone.update(fw_settings)

    elif a.version:
        __print_and_exit(fw.get_property("version"))
    elif a.state:
        state = fw.get_property("state")
        if state == "RUNNING":
            __print_and_exit ("running")
        else:
            __print_and_exit ("not running", NOT_RUNNING)
    elif a.reload:
        fw.reload()
    elif a.complete_reload:
        fw.complete_reload()
    elif a.direct:
        if a.passthrough:
            if len (a.passthrough) < 2:
                __fail("usage: --direct --passthrough { ipv4 | ipv6 | eb } <args>")
            __print(fw.passthrough(_check_ipv(a.passthrough[0]),
                                 a.passthrough[1:]))
        elif a.add_chain:
            fw.addChain(_check_ipv(a.add_chain[0]),
                        a.add_chain[1], a.add_chain[2])
        elif a.remove_chain:
            fw.removeChain(_check_ipv(a.remove_chain[0]),
                           a.remove_chain[1], a.remove_chain[2])
        elif a.query_chain:
            __print_query_result(fw.queryChain(_check_ipv(a.query_chain[0]),
                                       a.query_chain[1], a.query_chain[2]))
        elif a.get_chains:
            __print_and_exit(" ".join(fw.getChains(_check_ipv(a.get_chains[0]),
                                        a.get_chains[1])))
        elif a.get_all_chains:
            chains = fw.getAllChains()
            for (ipv, table, chain) in chains:
                __print("%s %s %s" % (ipv, table, chain))
            sys.exit(0)
        elif a.add_rule:
            if len (a.add_rule) < 5:
                __fail("usage: --direct --add-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>")
            try:
                priority = int(a.add_rule[3])
            except ValueError:
                __fail("wrong priority\nusage: --direct --add-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>")
            fw.addRule(_check_ipv(a.add_rule[0]), a.add_rule[1], a.add_rule[2],
                       priority, a.add_rule[4:])
        elif a.remove_rule:
            if len (a.remove_rule) < 5:
                __fail("usage: --direct --remove-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>")
            try:
                priority = int(a.remove_rule[3])
            except ValueError:
                __fail("usage: --direct --remove-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>")
            fw.removeRule(_check_ipv(a.remove_rule[0]),
                          a.remove_rule[1], a.remove_rule[2], priority, a.remove_rule[4:])
        elif a.query_rule:
            if len (a.query_rule) < 5:
                __fail("usage: --direct --query-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>")
            try:
                priority = int(a.query_rule[3])
            except ValueError:
                __fail("usage: --direct --query-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>")
            __print_query_result(fw.queryRule(_check_ipv(a.query_rule[0]),
                                      a.query_rule[1], a.query_rule[2], priority, a.query_rule[4:]))
        elif a.get_rules:
            rules = fw.getRules(_check_ipv(a.get_rules[0]),
                                a.get_rules[1], a.get_rules[2])
            for (priority, rule) in rules:
                __print("%d %s" % (priority, joinArgs(rule)))
            sys.exit(0)
        elif a.get_all_rules:
            rules = fw.getAllRules()
            for (ipv, table, chain, priority, rule) in rules:
                __print("%s %s %s %d %s" % (ipv, table, chain, priority,
                                            joinArgs(rule)))
            sys.exit(0)

    elif a.get_default_zone:
        __print_and_exit(fw.getDefaultZone())
    elif a.set_default_zone:
        fw.setDefaultZone(a.set_default_zone)
    elif a.get_zones:
        __print_and_exit(" ".join(fw.getZones()))
    elif a.get_active_zones:
        zones = fw.getActiveZones()
        for zone in zones:
            __print("%s" % (zone))
            for x in [ "interfaces", "sources" ]:
                if x in zones[zone]:
                    __print("  %s: %s" % (x, " ".join(zones[zone][x])))
        sys.exit(0)
    elif a.get_services:
        l = fw.listServices()
        __print_and_exit(" ".join(l))
    elif a.get_icmptypes:
        l = fw.listIcmpTypes()
        __print_and_exit(" ".join(l))

    # panic
    elif a.panic_on:
        fw.enablePanicMode()
    elif a.panic_off:
        fw.disablePanicMode()
    elif a.query_panic:
        __print_query_result(fw.queryPanicMode())

    # lockdown
    elif a.lockdown_on:
        fw.config().set_property("Lockdown", "yes")   # permanent
        fw.enableLockdown()                           # runtime
    elif a.lockdown_off:
        fw.config().set_property("Lockdown", "no")    # permanent
        fw.disableLockdown()                          # runtime
    elif a.query_lockdown:
        __print_query_result(fw.queryLockdown())      # runtime
        #lockdown = fw.config().get_property("Lockdown")
        #__print_query_result(lockdown.lower() in [ "yes", "true" ])

    # lockdown whitelist

    # commands
    elif a.list_lockdown_whitelist_commands:
        l = fw.getLockdownWhitelistCommands()
        __print_and_exit("\n".join(l))
    elif a.add_lockdown_whitelist_command:
        fw.addLockdownWhitelistCommand(a.add_lockdown_whitelist_command)
    elif a.remove_lockdown_whitelist_command:
        fw.removeLockdownWhitelistCommand(a.remove_lockdown_whitelist_command)
    elif a.query_lockdown_whitelist_command:
        __print_query_result(fw.queryLockdownWhitelistCommand( \
                             a.query_lockdown_whitelist_command))

    # contexts
    elif a.list_lockdown_whitelist_contexts:
        l = fw.getLockdownWhitelistContexts()
        __print_and_exit("\n".join(l))
    elif a.add_lockdown_whitelist_context:
        fw.addLockdownWhitelistContext(a.add_lockdown_whitelist_context)
    elif a.remove_lockdown_whitelist_context:
        fw.removeLockdownWhitelistContext(a.remove_lockdown_whitelist_context)
    elif a.query_lockdown_whitelist_context:
        __print_query_result(fw.queryLockdownWhitelistContext( \
                             a.query_lockdown_whitelist_context))

    # uids
    elif a.list_lockdown_whitelist_uids:
        l = fw.getLockdownWhitelistUids()
        __print_and_exit(" ".join(map(str, l)))
    elif a.add_lockdown_whitelist_uid:
        fw.addLockdownWhitelistUid(a.add_lockdown_whitelist_uid)
    elif a.remove_lockdown_whitelist_uid:
        fw.removeLockdownWhitelistUid(a.remove_lockdown_whitelist_uid)
    elif a.query_lockdown_whitelist_uid:
        __print_query_result(fw.queryLockdownWhitelistUid( \
                             a.query_lockdown_whitelist_uid))

    # users
    elif a.list_lockdown_whitelist_users:
        l = fw.getLockdownWhitelistUsers()
        __print_and_exit(" ".join(l))
    elif a.add_lockdown_whitelist_user:
        fw.addLockdownWhitelistUser(a.add_lockdown_whitelist_user)
    elif a.remove_lockdown_whitelist_user:
        fw.removeLockdownWhitelistUser(a.remove_lockdown_whitelist_user)
    elif a.query_lockdown_whitelist_user:
        __print_query_result(fw.queryLockdownWhitelistUser( \
                             a.query_lockdown_whitelist_user))

    # interface
    elif a.list_interfaces:
        l = fw.getInterfaces(zone)
        __print_and_exit(" ".join(l))
    elif a.get_zone_of_interface:
        zone = fw.getZoneOfInterface(a.get_zone_of_interface)
        if zone:
            __print_and_exit(zone)
        else:
            __print_and_exit("no zone", 2)
    elif a.add_interface:
        fw.addInterface(zone, a.add_interface)
    elif a.change_interface:
        fw.changeZoneOfInterface(zone, a.change_interface)
    elif a.remove_interface:
        fw.removeInterface(zone, a.remove_interface)
    elif a.query_interface:
        __print_query_result(fw.queryInterface(zone, a.query_interface))

    # source
    elif a.list_sources:
        sources = fw.getSources(zone)
        __print_and_exit(" ".join(sources))
    elif a.get_zone_of_source:
        zone = fw.getZoneOfSource(a.get_zone_of_source)
        if zone:
            __print_and_exit(zone)
        else:
            __print_and_exit("no zone", 2)
    elif a.add_source:
        fw.addSource(zone, a.add_source)
    elif a.change_source:
        fw.changeZoneOfSource(zone, a.change_source)
    elif a.remove_source:
        fw.removeSource(zone, a.remove_source)
    elif a.query_source:
        __print_query_result(fw.querySource(zone, a.query_source))

    # rich rules
    elif a.list_rich_rules:
        l = fw.getRichRules(zone)
        __print_and_exit("\n".join(l))
    elif a.add_rich_rule:
        for s in a.add_rich_rule:
            fw.addRichRule(zone, s, a.timeout)
    elif a.remove_rich_rule:
        for s in a.remove_rich_rule:
            fw.removeRichRule(zone, s)
    elif a.query_rich_rule:
        __print_query_result(fw.queryRichRule(zone, a.query_rich_rule))

    # service
    elif a.list_services:
        l = fw.getServices(zone)
        __print_and_exit(" ".join(l))
    elif a.add_service:
        for s in a.add_service:
            fw.addService(zone, s, a.timeout)
    elif a.remove_service:
        for s in a.remove_service:
            fw.removeService(zone, s)
    elif a.query_service:
        __print_query_result(fw.queryService(zone, a.query_service))

    # port
    elif a.list_ports:
        l = fw.getPorts(zone)
        __print_and_exit(" ".join(["%s/%s" % (port[0], port[1]) for port in l]))
    elif a.add_port:
        for port_proto in a.add_port:
            (port, proto) = __parse_port(port_proto)
            fw.addPort(zone, port, proto, a.timeout)
    elif a.remove_port:
        for port_proto in a.remove_port:
            (port, proto) = __parse_port(port_proto)
            fw.removePort(zone, port, proto)
    elif a.query_port:
        (port, proto) = __parse_port(a.query_port)
        __print_query_result(fw.queryPort(zone, port, proto))

    # masquerade
    elif a.add_masquerade:
        fw.addMasquerade(zone, a.timeout)
    elif a.remove_masquerade:
        fw.removeMasquerade(zone)
    elif a.query_masquerade:
        __print_query_result(fw.queryMasquerade(zone))

    # forward port
    elif a.list_forward_ports:
        l = fw.getForwardPorts(zone)
        __print_and_exit("\n".join(["port=%s:proto=%s:toport=%s:toaddr=%s" % (port, protocol, toport, toaddr) for (port, protocol, toport, toaddr) in l]))
    elif a.add_forward_port:
        for fp in a.add_forward_port:
            (port, protocol, toport, toaddr) = __parse_forward_port(fp)
            fw.addForwardPort(zone, port, protocol, toport, toaddr, a.timeout)
    elif a.remove_forward_port:
        for fp in a.remove_forward_port:
            (port, protocol, toport, toaddr) = __parse_forward_port(fp)
            fw.removeForwardPort(zone, port, protocol, toport, toaddr)
    elif a.query_forward_port:
        (port, protocol, toport, toaddr) = __parse_forward_port(a.query_forward_port)
        __print_query_result(fw.queryForwardPort(zone, port, protocol,
                                         toport, toaddr))

    # block icmp
    elif a.list_icmp_blocks:
        l = fw.getIcmpBlocks(zone)
        __print_and_exit(" ".join(l))
    elif a.add_icmp_block:
        for ib in a.add_icmp_block:
            fw.addIcmpBlock(zone, ib, a.timeout)
    elif a.remove_icmp_block:
        for ib in a.remove_icmp_block:
            fw.removeIcmpBlock(zone, ib)
    elif a.query_icmp_block:
        __print_query_result(fw.queryIcmpBlock(zone, a.query_icmp_block))

    # list all
    elif a.list_all:
        __list_all(fw, zone if zone else fw.getDefaultZone())
        sys.exit(0)

    # list everything
    elif a.list_all_zones:
        for zone in fw.getZones():
            __list_all(fw, zone)
            __print("")
        sys.exit(0)


except dbus.exceptions.DBusException as e:
    dbus_message = e.get_dbus_message()
    dbus_name = e.get_dbus_name()
    if "NotAuthorizedException" in dbus_name:
        __print ("Authorization failed.")
        __print ("Make sure polkit agent is running or run firewall-cmd as superuser.")
        sys.exit(NOT_AUTHORIZED)
    else:
        code = FirewallError.get_code(dbus_message)
        if code in [ ALREADY_ENABLED, NOT_ENABLED, ZONE_ALREADY_SET ]:
            __print_and_exit("Warning: %s" % dbus_message)
        else:
            __print_and_exit("Error: %s" % dbus_message, code)

__print_and_exit("success")
