#!/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 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)

def __exception_handler(exception_message):
    if "NotAuthorizedException" in exception_message:
        __print ("Authorization failed.")
        __print ("Make sure polkit agent is running or run the application as superuser.")
        sys.exit(NOT_AUTHORIZED)
    else:
        code = FirewallError.get_code(exception_message)
        if code in [ ALREADY_ENABLED, NOT_ENABLED, ZONE_ALREADY_SET ]:
            __print_and_exit("Warning: %s" % exception_message)
        else:
            __print_and_exit("Error: %s" % exception_message, code)

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
fw = FirewallClient()
fw.setExceptionHandler(__exception_handler)
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)

__print_and_exit("success")
