void ProjectPanel::findExternalRefs(FWObject *lib,
                                       FWObject *root,
                                       list<FWReference*> &extRefs)
{
    FWReference *ref=FWReference::cast(root);
    if (ref!=nullptr)
    {
        FWObject *plib = ref->getPointer()->getLibrary();
        if ( plib->getId()!=FWObjectDatabase::STANDARD_LIB_ID &&
             plib->getId()!=FWObjectDatabase::DELETED_OBJECTS_ID  &&
             plib!=lib )
            extRefs.push_back(ref);
        return;
    } else
    {
        for (FWObject::iterator i=root->begin(); i!=root->end(); i++)
            findExternalRefs(lib, *i, extRefs);

    }
}
void ObjectManipulator::lockObject()
{
    if (fwbdebug)
        qDebug() << "ObjectManipulator::lockObject selected:"
                 << getCurrentObjectTree()->getNumSelected();

    if (getCurrentObjectTree()->getNumSelected()==0) return;

    try
    {
        FWObject *obj;

        vector<FWObject*> so = getCurrentObjectTree()->getSimplifiedSelection();
        for (vector<FWObject*>::iterator i=so.begin();  i!=so.end(); ++i)
        {
            obj= *i;
            FWObject *lib = obj->getLibrary();
            // these lbraries are locked anyway, do not let the user
            // lock objects inside because they won't be able to unlock them.
            if (lib->getId()!=FWObjectDatabase::STANDARD_LIB_ID)
            {
                std::auto_ptr<FWCmdLockObject> cmd(
                    new FWCmdLockObject(m_project, obj, tr("Lock object ") +
                                        QString::fromUtf8(obj->getName().c_str())));
                FWObject* new_state = cmd->getNewState();
                new_state->setReadOnly(true);
                if (!cmd->getOldState()->cmp(new_state, true))
                    m_project->undoStack->push(cmd.release());
            }
        }
        // Arguably, locking an object should not change lastModified timestamp
        // because none of the attributes that affect generated policy change.
        //QCoreApplication::postEvent(
        //    mw, new dataModifiedEvent(m_project->getFileName(), 0));
    } catch (FWException &ex)
    {
        qDebug() << ex.toString().c_str();
    }
}
void ObjectManipulator::addSubfolderSlot()
{
    const QAction *qAct = dynamic_cast<const QAction *>(sender());
    if (qAct == 0) return;

    FWObject *obj = getCurrentObjectTree()->getCurrentObject();
    assert(obj->getId() == qAct->data().toInt());

    QString folder = QInputDialog::getText(0, tr("Add Subfolder"),
                                           tr("Enter new subfolder name"));
    folder = folder.simplified();
    if (folder.isEmpty()) return;
    if (folder.contains(',')) {
        QMessageBox::warning(this, "Firewall Builder",
                             tr("Subfolder cannot contain a comma"), "&OK",
                             QString::null, QString::null, 0, 1);
        return;
    }

    /* See if the subfolder already exists */
    string folderStr = folder.toUtf8().constData();
    set<string> folders = stringToSet(obj->getStr("subfolders"));
    if (folders.find(folderStr) != folders.end()) return;
    folders.insert(folderStr);

    if (fwbdebug) {
        qDebug() << "ObjectManipulator::addSubfolder: " << folder;
    }

    FWCmdAddUserFolder *cmd = new FWCmdAddUserFolder(m_project, obj, folder,
                                                     tr("Add subfolder"));
    FWObject *newObj = cmd->getNewState();
    newObj->setStr("subfolders", setToString(folders));

    m_project->undoStack->push(cmd);
}
void PolicyCompiler_pix::warnWhenTranslatedAddressesAreUsed::action(
    PolicyRule* policy_rule,
    NATRule* nat_rule, Address*, Address *dst, Service*)
{
//    FWObject *rule_iface = compiler->dbcopy->findInIndex(
//        policy_rule->getInterfaceId());

    RuleElementItf *intf_re = policy_rule->getItf();
    FWObject *rule_iface = FWObjectReference::getObject(intf_re->front());

    string version = compiler->fw->getStr("version");

    RuleElement *re;
    FWObject *o;

    re = nat_rule->getODst();
    o = FWReference::getObject(re->front());
    Address  *odst = Address::cast(o); assert(odst);

    FWObject *p = odst->getParent();

    if (odst->getId() == rule_iface->getId() ||
        p->getId() == rule_iface->getId())
    {
        QString err("Object %1 that represents translated address in a NAT rule %2 "
                    "is used in a policy rule of ASA v%3 firewall. "
                    "Starting with v8.3, ASA requires using real IP addresses "
                    "in the firewall policy rules. ");

        compiler->warning(
            policy_rule,
            err.arg(QString::fromUtf8(dst->getName().c_str()))
            .arg(nat_rule->getLabel().c_str())
            .arg(version.c_str()).toStdString());
    }
}
string PolicyCompiler::debugPrintRule(Rule *r)
{
    PolicyRule *rule=PolicyRule::cast(r);

//    FWOptions *ruleopt =rule->getOptionsObject();

    RuleElementSrc *srcrel = rule->getSrc();
    RuleElementDst *dstrel = rule->getDst();
    RuleElementSrv *srvrel = rule->getSrv();
    RuleElementItf *itfrel = rule->getItf();

//    int iface_id = rule->getInterfaceId();
//    Interface *rule_iface = Interface::cast(dbcopy->findInIndex(iface_id));

    ostringstream str;

//    str << setw(70) << setfill('-') << "-";

    int no=0;
    FWObject::iterator i1=srcrel->begin();
    FWObject::iterator i2=dstrel->begin(); 
    FWObject::iterator i3=srvrel->begin();
    FWObject::iterator i4=itfrel->begin();

    while ( i1!=srcrel->end() || i2!=dstrel->end() || i3!=srvrel->end() ||
            i4!=itfrel->end())
    {
        str << endl;

        string src=" ";
        string dst=" ";
        string srv=" ";
        string itf=" ";

        int src_id = -1;
        int dst_id = -1;
        int srv_id = -1;

        if (srcrel->getNeg()) src = "!";
        if (dstrel->getNeg()) dst = "!";
        if (srvrel->getNeg()) srv = "!";
        if (itfrel->getNeg()) itf = "!";

        if (i1!=srcrel->end())
        {
            FWObject *o = FWReference::getObject(*i1);
            src += o->getName();
            src_id = o->getId();
        }

        if (i2!=dstrel->end())
        {
            FWObject *o = FWReference::getObject(*i2);
            dst += o->getName();
            dst_id = o->getId();
        }

        if (i3!=srvrel->end())
        {
            FWObject *o = FWReference::getObject(*i3);
            srv += o->getName();
            srv_id = o->getId();
        }

        if (i4!=itfrel->end())
        {
            ostringstream str;
            FWObject *o = FWReference::getObject(*i4);
            str << o->getName() << "(" << o->getId() << ")";
            itf += str.str();
        }

        int w = 0;
        if (no==0)
        {
            str << rule->getLabel();
            w = rule->getLabel().length();
        }
        
        str <<  setw(10-w)  << setfill(' ') << " ";

        str <<  setw(18) << setfill(' ') << src.c_str() << "(" << src_id << ")";
        str <<  setw(18) << setfill(' ') << dst.c_str() << "(" << dst_id << ")";
        str <<  setw(12) << setfill(' ') << srv.c_str() << "(" << srv_id << ")";
        str <<  setw(8)  << setfill(' ') << itf.c_str();

        if (no==0)
        {
            str <<  setw(9)  << setfill(' ') << rule->getActionAsString().c_str();
            str <<  setw(12)  << setfill(' ') << rule->getDirectionAsString().c_str();
            if (rule->getLogging()) str << " LOG";
        } else
            str <<  setw(18)  << setfill(' ') << " ";

        ++no;

        if ( i1!=srcrel->end() ) ++i1;
        if ( i2!=dstrel->end() ) ++i2;
        if ( i3!=srvrel->end() ) ++i3;
        if ( i4!=itfrel->end() ) ++i4;
    }
    return str.str();
}
bool RoutingCompiler::classifyRoutingRules::processNext()
{

    assert(compiler!=NULL);
    assert(prev_processor!=NULL);

    slurp();

    if (tmp_queue.size()==0) return false;
    
    
    for (std::deque<libfwbuilder::Rule *>::iterator tmp_queue_it=tmp_queue.begin(); tmp_queue_it!=tmp_queue.end(); ++tmp_queue_it)
    {
        RoutingRule *rule = RoutingRule::cast( *tmp_queue_it);
        rule->setRuleType( RoutingRule::SinglePath);
        
        RuleElementRItf *itfrel=rule->getRItf();
        FWObject *itf = FWReference::cast(itfrel->front())->getPointer();
        
        RuleElementRGtw *gtwrel=rule->getRGtw();
        FWObject *gtw = FWReference::cast(gtwrel->front())->getPointer();
        
        string metric  = rule->getMetricAsString();
        string label   = rule->getSortedDstIds();
        ostringstream ostr;
        ostr << gtw->getId() << "_" << itf->getId();
        string combiId = ostr.str();
        
        if( label == "")
            compiler->abort(
                
                    rule,
                    "Place 'createSortedDstIdsLabel()' right before "
                    "'classifyRoutingRules()' in the rule processor chain");
        
        dest_it = rules_seen_so_far.find(label);
        if( dest_it != rules_seen_so_far.end()) {
            
            // a rule with the same destination was already seen
            //std::cout << "classifyRoutingRules:NO NEW DEST" << std::endl;///
            
            gtwitf_it = dest_it->second.find(combiId);
            if( gtwitf_it == dest_it->second.end() ) {
                
                // ... this gateway and interface combination is new for this destination
                //std::cout << "classifyRoutingRules:NEW GTWITF" << std::endl;///
                
                
                for( gtwitf_it = dest_it->second.begin(); gtwitf_it != dest_it->second.end(); gtwitf_it++) {
                    
                    if( gtwitf_it->second.first == metric) {
                        // ... but has the same metric as another rule with this Dst => multipath or abort
                        //std::cout << "classifyRoutingRules:SAME METRIC" << std::endl;///
                        
                        if(true) { //TODO: if ( compiler->fw->getOptionsObject()->getBool ("equal_cost_multi_path") )
                            
                            rule->setRuleType( RoutingRule::MultiPath);
                            gtwitf_it->second.second->setRuleType( RoutingRule::MultiPath);
                            
                            //std::cout << "classifyRoutingRules:the rules " << rule->getLabel() << " and " << gtwitf_it->second.second->getLabel() << " were set to multipath." << std::endl;///
                        }
                    }
                }
                
                dest_it->second[combiId] = pair< string, RoutingRule*>( metric, rule);
            }
            
        } else {
            
            // this destination is new
            //std::cout << "classifyRoutingRules:NEW DEST" << std::endl;///
             
            map< string, pair< string, RoutingRule*> > gtw_itf_tmp;
            gtw_itf_tmp[combiId] = pair< string, RoutingRule*>( metric, rule);
            rules_seen_so_far[label] = gtw_itf_tmp;
        }
    }
    
    return true;
}
bool RoutingCompiler::competingRules::processNext()
{
    RoutingRule *rule = getNext(); if (rule==NULL) return false;
        
    RuleElementRItf *itfrel = rule->getRItf();
    FWObject *itf = FWReference::cast(itfrel->front())->getPointer();
    
    RuleElementRGtw *gtwrel = rule->getRGtw();
    FWObject *gtw = FWReference::cast(gtwrel->front())->getPointer();
     
    string metric = rule->getMetricAsString();
    string label  = rule->getSortedDstIds();
    ostringstream ostr;
    ostr << gtw->getId() << "_" << itf->getId();
    string combiId = ostr.str();
    
    if( label == "") compiler->abort(
        
            rule,         
            "Place 'createSortedDstIdsLabel()' before 'competingRules()' "
            "in the rule processor chain");
    
    dest_it = rules_seen_so_far.find(label);
    if( dest_it != rules_seen_so_far.end()) {
        
        // a rule with the same destination was already seen
        ///std::cout << "NO NEW DEST" << std::endl;
        
        gtwitf_it = dest_it->second.find(combiId);
        if( gtwitf_it != dest_it->second.end() )
        {
            // ... this gateway and interface combination were already
            // seen for this destination
            ///std::cout << "NO NEW GTWITF" << std::endl;
            
            if( gtwitf_it->second.first == metric) {
                
                // ... and same metric => rule already exists, skip
                ///std::cout << "SAME METRIC" << std::endl;
                
                string msg;
                msg = "Routing rules " + gtwitf_it->second.second +
                    " and " + rule->getLabel() +
                    " are identical, skipping the second one. " +
                    "Delete one of them to avoid this warning";
                compiler->warning(rule,  msg.c_str());
            } else {
                
                // ... but different metric => what metric should I use? => abort
                ///std::cout << "DIFFERENT METRIC" << std::endl;
                
                string msg;
                msg = "Routing rules " + gtwitf_it->second.second +
                    " and " + rule->getLabel() +
                    " are identical except for the metric, " +
                    "please delete one of them";
                compiler->abort(rule,  msg.c_str());
            }
        
        } else
        {
            // ... this gateway and interface combination is new for
            // this destination
            ///std::cout << "NEW GTWITF" << std::endl;///
            
            if(false)
            {
                // TODO_lowPrio: if (
                // !compiler->fw->getOptionsObject()->getBool
                // ("equal_cost_multi_path") ) ...If multipath is
                // turned off, perform this check.

                // iterate all gtwitf combis in the map
                // dest_it->second and search for the current metric
                
                // ... but has the same metric => what route should I
                // use for this destination? => abort
                    
                string msg;
                msg = "Routing rules " + gtwitf_it->second.second + " and " +
                    rule->getLabel() +
                    " have the same destination and same metric,"
                    "but different gateway and interface combination. "
                    "Set the metrics to different values or "
                    "enable ECMP (Equal Cost MultiPath) routing";
                compiler->abort( msg.c_str() );
            
            } else
            {
                // ... and different metric OR equal_cost_multi_path enabled => OK
                tmp_queue.push_back(rule);
            }
            
            dest_it->second[combiId] =
                pair< string, string>( metric, rule->getLabel());
        }
        
    } else {
        
        // this destination is new
        //std::cout << "NEW DEST" << std::endl;
        ///
        
        //ruleinfo tmpRuleInfo = { gtw->getStr("id") + itf->getStr("id"), metric, rule->getLabel()};
        //rules_seen_so_far[label] = tmpRuleInfo;
        
        map< string, pair< string, string> > gtw_itf_tmp;
        gtw_itf_tmp[combiId] = pair< string, string>( metric, rule->getLabel());
        
        rules_seen_so_far[label] = gtw_itf_tmp;
        
        
        tmp_queue.push_back(rule);
    }

    return true;
}
void GroupObjectDialog::applyChanges()
{
    std::auto_ptr<FWCmdChange> cmd( new FWCmdChange(m_project, obj));
    FWObject* new_state = cmd->getNewState();

    string oldname = obj->getName();
    string newname = string(m_dialog->obj_name->text().toUtf8().constData());
    if (oldname != newname)
    {
        if (fwbdebug)
            qDebug() << "oldname=" << oldname.c_str()
                     << "newname=" << newname.c_str();
        new_state->setName(newname);
    }

    m_dialog->commentKeywords->applyChanges(new_state);

    set<int> oldobj;
    set<int> newobj;

    for (int it=0; it<listView->topLevelItemCount(); ++it)
    {
        QTreeWidgetItem *itm = listView->topLevelItem(it);
        int obj_id = itm->data(0, Qt::UserRole).toInt();
        newobj.insert(obj_id);
    }

    for (FWObject::iterator j=obj->begin(); j!=obj->end(); ++j)
    {
        FWObject *o = *j;
        if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
        oldobj.insert(o->getId());
    }

    set<int> diff;

    set_difference( oldobj.begin(), oldobj.end(),
                    newobj.begin(), newobj.end(),
                    inserter(diff,diff.begin()));
/* diff contains objects present in oldobj but not in newobj - these objects
   were deleted from the group */

    for (set<int>::iterator k=diff.begin(); k!=diff.end(); ++k)
    {
        FWObject *o = m_project->db()->findInIndex(*k);
        // Note: FWBTree::isSystem() would not work for new_state because
        // it is not part of the tree and isSystem() relies on the tree path
        if (FWBTree().isSystem(obj))
        {
            m_project->m_panel->om->deleteObject(o);
        } else
        {
            new_state->removeRef(o);
        }
    }

    diff.clear();

    set_difference( newobj.begin(), newobj.end(),
                    oldobj.begin(), oldobj.end(),
                    inserter(diff,diff.begin()));
/* diff contains objects present in newobj but not in oldobj - these objects
   were added to the group */

    for (set<int>::iterator k1=diff.begin(); k1!=diff.end(); ++k1)
    {
        FWObject *o = m_project->db()->findInIndex(*k1);
        if (FWBTree().isSystem(obj))
        {
            m_project->pasteTo(new_state, o);
        } else
        {
            new_state->addRef(o);
        }
    }

    saveColumnWidths();

    if (!cmd->getOldState()->cmp(new_state, true))
    {
        if (obj->isReadOnly()) return;
        m_project->undoStack->push(cmd.release());
    }
}
void CompilerDriver_pix::pixNetworkZoneChecks(Firewall *fw,
                                              list<FWObject*> &all_interfaces)
{
    multimap<string, FWObject*> netzone_objects;
    Helper helper(NULL);

    for (std::list<FWObject*>::iterator i=all_interfaces.begin(); i!=all_interfaces.end(); ++i)
    {
        Interface *iface = dynamic_cast<Interface*>(*i);
        assert(iface);

        if (iface->getOptionsObject()->getBool("cluster_interface")) continue;
        if (iface->isDedicatedFailover()) continue;
        if (iface->isUnprotected()) continue;


        /*
         * in PIX, we need network zones to be defined for all
         * interfaces
         */
        string netzone_id = iface->getStr("network_zone");
        if (netzone_id=="")
        {
            QString err("Network zone definition is missing for interface '%1' (%2)");
            abort(fw, NULL, NULL,
                  err.arg(iface->getName().c_str())
                  .arg(iface->getLabel().c_str()).toStdString());
            throw FatalErrorInSingleRuleCompileMode();
        }

        FWObject *netzone = objdb->findInIndex(
            FWObjectDatabase::getIntId(netzone_id));
        if (netzone==NULL) 
        {
            QString err("Network zone points at nonexisting object for "
                        "interface '%1' (%2)");
            abort(fw, NULL, NULL,
                  err.arg(iface->getName().c_str())
                  .arg(iface->getLabel().c_str()).toStdString());
            throw FatalErrorInSingleRuleCompileMode();
        }
/*
 * netzone may be a group, in which case we need to expand it
 * (recursively). 
 * 
 * 1. We create new temporary object (type Group).
 *
 * 2. put it in the database somewhere
 *
 * 3. add all objects that belong to the network zone to this
 * group. We add objects directly, not as a reference.
 *
 * 4. finally replace reference to the old network zone object in the
 * interface with reference to this new group.
 *
 * 5. we store ID of the original network zone object 
 *    using iface->setStr("orig_netzone_id")
 *
 * This ensures netzones do not contain other groups and do not
 * require any recursive expanding anymore. Since objects were added
 * to netzones directly, we do not need to bother with dereferencing,
 * too.
 */
        list<FWObject*> ol;
        helper.expand_group_recursive(netzone, ol);

        FWObject *nz = objdb->createObjectGroup();
        assert(nz!=NULL);
        nz->setName("netzone_" + iface->getLabel());
        objdb->add(nz);

        for (list<FWObject*>::iterator j=ol.begin(); j!=ol.end(); ++j)
        {
            Address *addr = Address::cast(*j);
            if (addr == NULL || addr->getAddressPtr() == NULL)
            {
                QString err("Network zone of interface '%1' uses object '%2' "
                            "that is not an address");
                abort(fw, NULL, NULL,
                      err.arg(iface->getLabel().c_str())
                      .arg((*j)->getName().c_str()).toStdString());
                throw FatalErrorInSingleRuleCompileMode();
            }

/*
  Commented out for SF bug 3213019

  currently we do not support ipv6 with PIX/ASA and FWSM. If user
  creates a group to be used as network zone object and places ipv6
  address in it, this address should be ignored while compiling the
  policy but this should not be an error. Compiler uses network zone
  group to do various address matching operations when it tries to
  determine an interface for a rule where user did not specify
  one. Since we never (should) have ipv6 in policy and nat rules,
  compiler is not going to have anything to compare to ipv6 address in
  the network zone even if there is one and this ipv6 address is going
  to be ignored.


            if (addr->getAddressPtr()->isV6())
            {
                QString err("Network zone of interface '%1' uses object '%2' "
                            "that is IPv6 address");
                abort(fw, NULL, NULL,
                      err.arg(iface->getLabel().c_str())
                      .arg((*j)->getName().c_str()).toStdString());
                throw FatalErrorInSingleRuleCompileMode();
            }
*/
            netzone_objects.insert(
                pair<string,FWObject*>(iface->getLabel(),*j));
            nz->addRef(*j);
        }
        iface->setStr("orig_netzone_id", netzone_id );
        iface->setStr("network_zone",
                      FWObjectDatabase::getStringId(nz->getId()) );
    }


/*
 * the same object (network or host) can not belong to network zones
 * of two different interfaces. Map netzone_objects holds pairs
 * interface_id/object. We just make sure the same object does not
 * appear in two pairs with different interfaces.
 */
    multimap<string,FWObject*>::iterator k;
    for (k=netzone_objects.begin(); k!=netzone_objects.end(); ++k)
    {
        multimap<string,FWObject*>::iterator l;
        l=k;
        ++l;
        for ( ; l!=netzone_objects.end(); ++l)
        {
            if ( l->second->getId() == k->second->getId() )
            {
                if (k->first==l->first)
                {
                    QString err("Object %1 is used more than once in network "
                                "zone of interface '%2'");
                    abort(fw, NULL, NULL,
                          err.arg(l->second->getName().c_str())
                          .arg(k->first.c_str()).toStdString());
                    throw FatalErrorInSingleRuleCompileMode();
                } else
                {
                    QString err("Object %1 is used in network zones of "
                                "interfaces '%2' and '%3'");
                    abort(fw, NULL, NULL,
                          err.arg(l->second->getName().c_str())
                          .arg(k->first.c_str())
                          .arg(l->first.c_str()).toStdString());
                    throw FatalErrorInSingleRuleCompileMode();
                }
            }
        }
    }


}
bool FWObjectDatabase::_findWhereObjectIsUsed(FWObject *o,
                                              FWObject *p,
                                              std::set<FWObject *> &resset,
                                              int search_id)
{
    bool res = false;
    if ( _isInIgnoreList(p)) return res;
    if (p->size()==0) return res;
    if (p->getInt(".search_id")==search_id) return p->getBool(".searchResult");

// set flags to break indefinite recursion in case we encounter circular groups
    p->setInt(".search_id", search_id);
    p->setBool(".searchResult", false);

    Interface *intf = Interface::cast(p);
    if (intf)
    {
        string netzone_id = intf->getStr("network_zone");
        FWObject *netzone = findInIndex(FWObjectDatabase::getIntId(netzone_id));
        if (netzone == o)
        {
            resset.insert(p);
            res = true;
        }
    }

    PolicyRule *rule = PolicyRule::cast(p);
    if (rule)
    {
        if (rule->getAction() == PolicyRule::Branch)
        {
            FWObject *ruleset = rule->getBranch();
            if (o==ruleset)
            {
                resset.insert(p);
                res = true;
            }
        }

        if (rule->getTagging())
        {
            FWObject *tagobj = rule->getTagObject();
            if (o==tagobj)
            {
                resset.insert(p);
                res = true;
            }
        }
    }

    NATRule *nat_rule = NATRule::cast(p);
    if (nat_rule && nat_rule->getAction() == NATRule::Branch)
    {
        FWObject *ruleset = nat_rule->getBranch();
        if (o==ruleset)
        {
            resset.insert(p);
            res = true;
        }
    }

    if (Firewall::isA(o) && Cluster::isA(p))
    {
        if (Cluster::cast(p)->hasMember(Firewall::cast(o)))
        {
            resset.insert(p);
            res = true;
        }
    }
   
    FWObject::iterator i1 = p->begin();
    for ( ; i1!=p->end(); ++i1)
    {
        FWReference  *ref = FWReference::cast(*i1);
        if (ref!=nullptr)
        {  // child is a reference
            FWObject *g = ref->getPointer();
            if (o->getId() == g->getId())
            {
                resset.insert(*i1);
                res = true;
            }
        }
        else    // child is a regular object, not a reference
        {
            if (o->getId() == (*i1)->getId())
            {
                resset.insert(p);
                res = true;
                // still run search recursively, the same object could be
                // used in rules if it is a firewall
            }
            _findWhereObjectIsUsed(o, *i1, resset, search_id);
        }
    }

    p->setBool(".searchResult", res);
    return res;
}
void PolicyCompiler_pix::replaceTranslatedAddresses::action(
    PolicyRule* policy_rule,
    NATRule* nat_rule, Address *src, Address*, Service *srv)
{

//    FWObject *rule_iface = compiler->dbcopy->findInIndex(
//        policy_rule->getInterfaceId());

    RuleElementItf *intf_re = policy_rule->getItf();
    FWObject *rule_iface = FWObjectReference::getObject(intf_re->front());

    RuleElement *re = nat_rule->getOSrc();

    FWObject *o = FWReference::getObject(re->front());
#ifndef NDEBUG
    Address  *osrc = Address::cast(o); assert(osrc);
#endif

    re = nat_rule->getODst();
    o = FWReference::getObject(re->front());
    Address  *odst = Address::cast(o); assert(odst);

    re = nat_rule->getOSrv();
    o = FWReference::getObject(re->front());
    Service  *osrv = Service::cast(o); assert(osrv);

#ifndef NDEBUG
    re = nat_rule->getTSrc();
    o = FWReference::getObject(re->front());
    Address  *tsrc = Address::cast(o); assert(tsrc);

    re = nat_rule->getTDst();
    o = FWReference::getObject(re->front());
    Address  *tdst = Address::cast(o); assert(tdst);

    re = nat_rule->getTSrv();
    o = FWReference::getObject(re->front());
    Service  *tsrv = Service::cast(o); assert(tsrv);
#endif

    FWObject *p = odst->getParent();

    if (odst->getId() == rule_iface->getId() ||
        p->getId() == rule_iface->getId())
    {

        PolicyRule  *r = compiler->dbcopy->createPolicyRule();
        compiler->temp_ruleset->add(r);
        r->duplicate(policy_rule);

        RuleElementSrc *nsrc = r->getSrc();
        nsrc->clearChildren();
        nsrc->addRef( src );

        RuleElementDst *ndst = r->getDst();
        ndst->clearChildren();
        ndst->addRef( odst );

        RuleElementSrv *nsrv = r->getSrv();
        nsrv->clearChildren();

        if (osrv->isAny())
            nsrv->addRef( srv );
        else
            nsrv->addRef( osrv );

        transformed_rules.push_back(r);
    }

}
bool ProjectPanel::event(QEvent *event)
{
    if (event->type() >= QEvent::User)
    {
        fwbUpdateEvent *ev = dynamic_cast<fwbUpdateEvent*>(event);
        int event_code = event->type() - QEvent::User;
        QString data_file = ev->getFileName();
        int obj_id = ev->getObjectId();
        FWObject *obj = db()->findInIndex(obj_id);

        if (fwbdebug)
            qDebug() << this
                     << "rcs:"
                     << rcs
                     << "rcs->getFileName():"
                     << QString((rcs!=NULL) ? rcs->getFileName() : "")
                     << "file:"
                     << data_file
                     << "event:"
                     << ev->getEventName()
                     << "object:"
                     << ((obj!=NULL) ? QString::fromUtf8(obj->getName().c_str()) : "")
                     << "(" << ((obj!=NULL) ? obj->getTypeName().c_str() : "") << ")"
                     << "id=" << ((obj!=NULL) ? obj->getId() : -1);

        if (event_code == UPDATE_GUI_STATE_EVENT && mdiWindow != NULL)
        {
            m_panel->om->updateCreateObjectMenu(getCurrentLib());
            ev->accept();
            return true;
        }

        if ((rcs && rcs->getFileName() == data_file) ||
            (!rcs && data_file.isEmpty()))
        {
            switch (event_code)
            {
            case RELOAD_OBJECT_TREE_EVENT:
                registerTreeReloadRequest();
                ev->accept();
                return true;
                
            case RELOAD_OBJECT_TREE_IMMEDIATELY_EVENT:
                m_panel->om->reload();
                ev->accept();
                return true;
                
            case RELOAD_RULESET_EVENT:
                registerRuleSetRedrawRequest();
                // update rule set title as well
                //updateFirewallName();
                ev->accept();
                return true;

            case MAKE_CURRENT_RULE_VISIBLE_IN_RULESET_EVENT:
            {
                RuleSetView* rsv = getCurrentRuleSetView();
                if (rsv) rsv->makeCurrentRuleVisible();
                ev->accept();
                return true;
            }
   
            case RELOAD_RULESET_IMMEDIATELY_EVENT:
                redrawRuleSets();
                //reopenFirewall();
                // update rule set title as well
                //updateFirewallName();
                ev->accept();
                return true;
            }

            if (obj == NULL) return false;

            switch (event_code)
            {
            case DATA_MODIFIED_EVENT:
            {
                // This event does not trigger any updates in the UI,
                // this purely data structure update event. 

                FWObject *p = obj;
                while (p && Firewall::cast(p)==NULL) p = p->getParent();
                Firewall *f = Firewall::cast(p);
                // when user locks firewall object, this code tries to
                // update last_modified timestamp in it because it
                // depends on itself. Dont.
                if (f && !f->isReadOnly())
                {
                    f->updateLastModifiedTimestamp();
                    QCoreApplication::postEvent(
                        mw, new updateObjectInTreeEvent(data_file, f->getId()));
                }
                registerModifiedObject(obj);

                QCoreApplication::postEvent(mw, new updateGUIStateEvent());

                ev->accept();
                return true;
            }

            case UPDATE_OBJECT_EVERYWHERE_EVENT:
            {
                Rule *rule = NULL;
                RuleSet* current_ruleset = NULL;
                RuleSetView* rsv = getCurrentRuleSetView();
                RuleSetModel* md = NULL;
                if (rsv)
                {
                    md = (RuleSetModel*)rsv->model();
                    current_ruleset = md->getRuleSet();
                }
                if (RuleElement::cast(obj)) rule = Rule::cast(obj->getParent());
                if (Rule::cast(obj)) rule = Rule::cast(obj);

                if (rule && current_ruleset && md && rule->isChildOf(current_ruleset))
                {
                    md->rowChanged(md->index(rule, 0));
                    ev->accept();
                    return true;
                }

                if (rule)
                {
                    QCoreApplication::postEvent(
                        this, new showObjectInRulesetEvent(data_file, obj_id));
                    ev->accept();
                    return true;
                }

                if (rsv) rsv->updateObject(obj);

                if (Library::cast(obj))
                {
                    m_panel->om->updateLibName(obj);
                    m_panel->om->updateLibColor(obj);
                }

                QCoreApplication::postEvent(
                    mw, new updateObjectInTreeEvent(data_file, obj_id));

                // QCoreApplication::postEvent(
                //     this, new reloadRulesetEvent(data_file));

                ev->accept();
                return true;
            }

            case OBJECT_NAME_CHANGED_EVENT:
            {
                objectNameChangedEvent *name_change_event =
                    dynamic_cast<objectNameChangedEvent*>(event);
                m_panel->om->updateObjectInTree(obj);
                if (name_change_event->rename_children)
                {
                    // This performs automatic renaming of child objects if necessary
                    m_panel->om->autoRenameChildren(obj, name_change_event->old_name);
                }
                ev->accept();
                return true;
            }

            case UPDATE_LAST_COMPILED_TIMESTAMP_EVENT:
                if (rcs && !rcs->isRO() &&
                    Firewall::cast(obj) && !obj->isReadOnly())
                {
                    Firewall::cast(obj)->updateLastCompiledTimestamp();
                    QCoreApplication::postEvent(
                        mw, new updateObjectInTreeEvent(data_file, obj_id));
                    ev->accept();
                    return true;
                }
                break;

            case UPDATE_LAST_INSTALLED_TIMESTAMP_EVENT:
                if (rcs && !rcs->isRO() &&
                    Firewall::cast(obj) && !obj->isReadOnly())
                {
                    Firewall::cast(obj)->updateLastInstalledTimestamp();
                    QCoreApplication::postEvent(
                        mw, new updateObjectInTreeEvent(data_file, obj_id));
                    ev->accept();
                    return true;
                }
                break;
            }

            // Events below this should only be processed if
            // ProjectPanel has been attached to an MDI window.  There
            // is no MDI window right after project panel is created
            // but some operations may already be performed. See
            // FWWindow::fileOpen where ProjectPanel is cfeated and
            // file is opened before MDI window is attached. So the UI
            // update events below will only be processed if MDI
            // window exists.

            if (mdiWindow == NULL) return false;

            switch (event->type() - QEvent::User)
            {
            case INSERT_OBJECT_IN_TREE_EVENT:
            {
                FWObject *parent =
                    db()->findInIndex(
                        dynamic_cast<insertObjectInTreeEvent*>(event)->parent_id);
                m_panel->om->insertSubtree(parent, obj);
                ev->accept();
                return true;
            }

            case REMOVE_OBJECT_FROM_TREE_EVENT:
            {
                m_panel->om->removeObjectFromTreeView(obj);
                ev->accept();
                return true;
            }

            case ADD_TREE_PAGE_EVENT:
                m_panel->om->addLib(obj);
                ev->accept();
                return true;

            case REMOVE_TREE_PAGE_EVENT:
                m_panel->om->removeLib(obj);
                ev->accept();
                return true;

            case UPDATE_OBJECT_IN_TREE_EVENT:
                registerObjectToUpdateInTree(obj, false);
                ev->accept();
                return true;

            case UPDATE_OBJECT_AND_SUBTREE_IN_TREE_EVENT:
                registerObjectToUpdateInTree(obj, true);
                ev->accept();
                return true;

            case UPDATE_OBJECT_AND_SUBTREE_IMMEDIATELY_EVENT:
                m_panel->om->updateObjectInTree(obj, true);
                ev->accept();
                return true;

            case OPEN_RULESET_EVENT:
                openRuleSet(obj);
                // update rule set title as well
                //updateFirewallName();
                ev->accept();
                return true;

            case OPEN_RULESET_IMMEDIATELY_EVENT:
                openRuleSet(obj, true);
                // update rule set title as well
                //updateFirewallName();
                ev->accept();
                return true;

            case SELECT_RULE_ELEMENT_EVENT:
            {
                RuleSetView* rsv = getCurrentRuleSetView();
                rsv->selectRE(Rule::cast(obj),
                              dynamic_cast<selectRuleElementEvent*>(event)->column_type);
                rsv->setFocus(Qt::OtherFocusReason);
                ev->accept();
                return true;
            }

            case SHOW_OBJECT_IN_RULESET_EVENT:
            {
                // if obj is child of RuleElement (i.e. a reference object)
                FWReference *ref = FWReference::cast(obj);
                if (ref)
                {
                    RuleSet* current_ruleset = NULL;
                    RuleSetView* rsv = getCurrentRuleSetView();
                    RuleSetModel* md = NULL;
                    if (rsv)
                    {
                        md = (RuleSetModel*)rsv->model();
                        current_ruleset = md->getRuleSet();
                    }

                    if (current_ruleset && obj->isChildOf(current_ruleset))
                    {
                        clearManipulatorFocus();
                        rsv->selectRE(ref);
                        rsv->setFocus(Qt::OtherFocusReason);
                    } else
                    {
                        FWObject *rs = obj;
                        while (rs && RuleSet::cast(rs)==NULL) rs = rs->getParent();
                        if (rs)
                        {
                            // reopen rule set right now, before we post event
                            // to show the object in it.
                            openRuleSet(rs);
                            QCoreApplication::postEvent(
                                this, new showObjectInRulesetEvent(data_file, obj_id));
                        }
                    }
                    ev->accept();
                    return true;
                }

                // if obj is RuleElement - select its first element
                RuleElement *re = RuleElement::cast(obj);
                if (re && re->size() > 0)
                {
                    QCoreApplication::postEvent(
                        this, new showObjectInRulesetEvent(data_file, obj->front()->getId()));
                    ev->accept();
                    return true;
                }

                // if obj is Rule - select its comment (the only common rule element)
                Rule *rule = Rule::cast(obj);
                if (rule)
                {
                    RuleSet* current_ruleset = NULL;
                    RuleSetView* rsv = getCurrentRuleSetView();
                    RuleSetModel* md = NULL;
                    if (rsv)
                    {
                        md = (RuleSetModel*)rsv->model();
                        current_ruleset = md->getRuleSet();
                    }
                    if (current_ruleset && rule->isChildOf(current_ruleset))
                    {
                        rsv->selectRE(rule, ColDesc::Comment);
                        rsv->setFocus(Qt::OtherFocusReason);
                        ev->accept();
                        return true;
                    } else
                    {
                        // this rule does not belong to the current ruleset
                        // reopen rule set right now, before we post event
                        // to show the object in it.
                        openRuleSet(rule->getParent(), true);
                        QCoreApplication::postEvent(
                            this, new showObjectInRulesetEvent(data_file, obj->getId()));
                    }
                    ev->accept();
                    return true;
                }

                ev->accept();
                return true;
            }

            case SHOW_OBJECT_IN_TREE_EVENT:
                //m_panel->om->setFocus();
                m_panel->om->openObjectInTree(obj);
                ev->accept();
                return true;

            case EXPAND_OBJECT_IN_TREE:
                m_panel->om->expandObjectInTree(obj);
                ev->accept();
                return true;

            case OPEN_LIBRARY_FOR_OBJECT_EVENT:
                m_panel->om->openLibForObject(obj);
                ev->accept();
                return true;

            case CLOSE_OBJECT_EVENT:
                if (RuleSet::cast(obj))
                {
                    if (visibleRuleSet == obj)
                    {
                        clearFirewallTabs();
                        closeRuleSet(obj);
                    }
                } else
                {
                    m_panel->om->closeObject();
                    mdiWindow->update();
                }
                ev->accept();
                return true;

            case ADD_USER_FOLDER_EVENT:
                m_panel->om->addUserFolderToTree(obj, dynamic_cast<addUserFolderEvent *>(event)->m_userFolder);
                ev->accept();
                return true;

            case REMOVE_USER_FOLDER_EVENT:
                m_panel->om->removeUserFolderFromTree(obj, dynamic_cast<removeUserFolderEvent *>(event)->m_userFolder);
                ev->accept();
                return true;

            case MOVE_TOFROM_USER_FOLDER_EVENT:
                moveToFromUserFolderEvent *moveEvent =
                    dynamic_cast<moveToFromUserFolderEvent *>(event);
                m_panel->om->moveToFromUserFolderInTree(obj, db()->findInIndex(moveEvent->m_objIdToMove), moveEvent->m_oldFolder, moveEvent->m_newFolder);
                ev->accept();
                return true;
            }
        }
        return false;
    }

    //if (fwbdebug) qDebug() << this << "event:" << event;
    
    return QWidget::event(event);
}
static bool isInDeletedObjs(FWObject *obj)
{
    FWObject *lib = obj->getLibrary();
    return lib == 0 || lib->getId() == FWObjectDatabase::DELETED_OBJECTS_ID;
}
void instDialog::setFlags(QTreeWidgetItem* item)
{
    int obj_id = item->data(0, Qt::UserRole).toInt();
    Firewall *fw = Firewall::cast(project->db()->findInIndex(obj_id));
    QTreeWidgetItem* parent = item->parent();

    time_t lm = fw->getInt("lastModified");
    time_t lc = fw->getInt("lastCompiled");
    time_t li = fw->getInt("lastInstalled");
    QDateTime dt;

    if (fwbdebug)
    {
        qDebug() << "instDialog::setFlags"
                 << item->text(0)
                 << "parent=" << parent
                 << "fw=" << fw
                 << "Firewall::isA(fw)=" << Firewall::isA(fw)
                 << "lm=" << lm
                 << "lc=" << lc
                 << "li=" << li
                 << "compile_only=" << compile_only;
        qDebug() << "fw->needsCompile()" << fw->needsCompile()
                 << "checkIfNeedToCompile(fw)=" << checkIfNeedToCompile(fw);
    }

    // need to skip the secondary cluster members if platform only
    // allows installations on the primary (e.g. PIX).  Note that
    // platform attribute must be the same in the cluster and member
    // firewalls objects. See #998

    string platform = fw->getStr("platform");
    bool install_only_on_primary_member = Resources::getTargetCapabilityBool(
        platform, "install_only_on_primary");

    Cluster *cluster = NULL;
    FWObject *master_interface = NULL;

    if (parent)
    {
        int obj_id = parent->data(0, Qt::UserRole).toInt();
        cluster = Cluster::cast(project->db()->findInIndex(obj_id));
        if (cluster)
        {
            FWObject *state_sync_group =
                cluster->getFirstByType(StateSyncClusterGroup::TYPENAME);
            // use state sync group to find which member firewall is
            // master.  This is only needed for platforms that install
            // only on master (PIX at this time)
            if (state_sync_group)
            {
                string master_id = state_sync_group->getStr("master_iface");
                for (FWObjectTypedChildIterator grp_it =
                         state_sync_group->findByType(FWObjectReference::TYPENAME);
                     grp_it != grp_it.end(); ++grp_it)
                {
                    FWObject *iface = FWObjectReference::getObject(*grp_it);
                    if (FWObjectDatabase::getStringId(iface->getId()) == master_id)
                    {
                        master_interface = iface;
                        break;
                    }
                }
            }
        }
    }

    // Real firewalls get checkbox for install
    if (Firewall::isA(fw))
    {
        bool checked = false;

        if (!compile_only)
        {
            checked = checkIfNeedToInstall(fw);
            if (cluster)
            {
                // override if checkIfNeedToCompile() is true for the
                // parent cluster.
                if (checkIfNeedToCompile(cluster))
                {
                    checked = true;
                }
            }
            item->setCheckState(INSTALL_CHECKBOX_COLUMN,
                                checked?Qt::Checked:Qt::Unchecked);

            // If this platform requires installation only on
            // the master, disable and uncheck checkbox for the standby.
            if (install_only_on_primary_member && master_interface != NULL)
            {
                QString txt = item->text(0);
                if (master_interface->isChildOf(fw))
                {
                    // Master
                    item->setText(0, QString("%1 (master)").arg(txt));
                } else
                {
                    // Standby
                    item->setText(0, QString("%1 (standby)").arg(txt));
                    item->setCheckState(INSTALL_CHECKBOX_COLUMN, Qt::Unchecked);
                    item->setFlags(0);
                }
            }
        }

        if (cluster==NULL)
        {
            // we are adding firewall that is not cluster member, it
            // needs "compile" checkbox
            checked = checkIfNeedToCompile(fw);
            item->setCheckState(COMPILE_CHECKBOX_COLUMN,
                                checked?Qt::Checked:Qt::Unchecked);
        }
    }

    int num_members = 0;
    // Clusters only get checkbox for compile, and only if they have members.
    if (Cluster::isA(fw))
    {
        list<Firewall*> members;
        Cluster::cast(fw)->getMembersList(members);
        num_members = members.size();
        if (num_members)
        {
            bool checked = checkIfNeedToCompile(fw);
            item->setCheckState(COMPILE_CHECKBOX_COLUMN,
                                checked?Qt::Checked:Qt::Unchecked);
        }
    }

    dt.setTime_t(lm);
    item->setText(LAST_MODIFIED_COLUMN, (lm)?dt.toString():QString("Never"));

    dt.setTime_t(lc);
    item->setText(LAST_COMPILED_COLUMN, (lc)?dt.toString():QString("Never"));

    dt.setTime_t(li);
    item->setText(LAST_INSTALLED_COLUMN, (li)?dt.toString():QString("Never"));
}